Tein tästä aiheesta jo kertaalleen kyselyn täällä foorumilla, mutta haluaisin vielä varmistaa seuraavan asian.
Minun palvelimella, jossa pyöritän PHP-sivuja ja MySQL-tietokantoja on magic_quotes_gpc ON, niin riittääkö tämä ajvn antama vinkki tekstimuotoisen muuttujan siivoamiseen niin, että sen voisi sitten tietokantalauseisiin laittaa:
//tekstikenttien vastaanottamiseen, nyt siis käytössä MySQL-tietokanta. function get_user_text($data){ return get_magic_quotes_gpc() ? mysql_real_escape_string((stripslashes($data)) : mysql_real_escape_string($data); }
Tuon koodin otin tästä aiheesta ja se löytyy kohdasta "ajv [23.02.2006 11:22:34]"
https://www.ohjelmointiputka.net/keskustelu/11573-kommentointilomake-apua
Tuo koodi näytästää jotenkin kummalliselta kun siinä on tuo kysymysmerkki get_magic_quotes_gpc() perässä, mutta tuo on ilmeisesti sama kuin tämä, joka on omaan silmään selkeämpi:
function filter_text($data){ if ( get_magic_quotes_gpc() == 1 ) return mysql_real_escape_string(stripslashes($data)); else return mysql_real_escape_string($data); }
Lisäys:
Löysinpä tällaisen ohjeen syötteiden siivoukseen:
if (!get_magic_quotes_gpc()) { $username = addslashes($username); $password = addslashes($password); }
Riittäisikö tuon pohjalta tehty funktio syötteen tarkistukseen:
function filter_text($data){ if ( !get_magic_quotes_gpc() ) return addslashes($data); else return $data; }
Huomautus:
Alan olla melko pihalla kohta näistä syötteen tarkistuksista.. Miksi noihin tekstimuotoisiin muuttujiin pitäisi lisätä tavaraa (esim. tuo addslashes), kun ei eikö niistä pitäisi vain poistaa jotain mahdollisia pätkiä, mitä joku voi vaikka tekstikenttään kirjoitella?
Tuo minun koodini ja sitä seuraava ajavat saman asian. Itse vain olen laiska koodari ja en jaksa tuollaiseen operaatioon tuhrata neljää koodiriviä, kun yhdelläkin pääsee :)
Nuo kaksi viimeistä eivät aja samaa asiaa kuin minun koodini. addslashes() ei vastaa mysql_real_escape_string()-funktiota, eikä myöskään magic_quotesit. Vaikkakin simppelimmän injektion nekin estävät.
mysql_real_escape_string()-funktiota voi käyttää vasta sen jälkeen, kun tietokantayhteys on luotu. Tästä on se hyöty, että silloin funktio osaa automaattisesti haistella tietokannan käyttämän merkistökoodauksen ja "escapettaa" sille merkistökoodaukselle haitalliset merkit.
Tekstimuotoisiin muuttujiin pitää lisätä takakenoja, jotta "varatut" merkit (esim hipsut) menevät oikein kantaan. Eihän ole mitenkään epänormaalia, että tekstissä esiintyy hipsuja? Lisää infoa tuosta SQL-injektiosta vaikka kuhan wikistä:
http://wiki.mureakuha.com/wiki/SQL-injektio
Ok, eli tiivistetäänpä vielä tulos niin joku muukin voi vaikka hyötyä joku päivä tästä. :)
formin_kasittelija.php
include 'tarkistaja.php'; // Haetaan formin syötteet muuttujiin $login = filter_text($_POST['login']); $pass = filter_text($_POST['pass']); $query = "SELECT login, pass FROM user WHERE login = '$login' AND pass = '$pass'"; $result = mysql_query($query);
tarkistaja.php
// Jos palvelimella on käytössä magic quotesit, niin poistetaan takakenot function filter_text($data){ $data = strip_tags($data); // TODO: Avataan tässä välissä tietokantayhteys if ( !get_magic_quotes_gpc() ) $data = mysql_real_escape_string($data); // TODO: Suljetaan tietokantayhteys return $data; }
Eli näillä tarkistuksilla saataisiin turvallista tietoa muuttujiin, että sitä arvaa laittaa tietokantalauseisiin? :o
Muokattu syötteen tarkistusfunktiota
Ei tuota tietokantayhteyttä tarvitse avata erikseen tuolla funktiossa, riittää, että se on auki ennen funktiokutsua. Yleensähän tietokantayhteys avataan aina heti sivun alussa ja suljetaan sivun lopussa.
Ja mitä tuohon edellä mainitsrmaasi funktioon tulee, niin jos magic_quotesit ovat päällä, et silloin aja syötettä mysql_real_escape_string()-funktion läpi. Syöte pitää aina ajaa sen läpi. Tuo alussa esittelemäsi funktio on edelleen se ainut oikea tapa tehdä tuo, älä turhaan yritä tehdä asioista vaikeampia kun ne ovat :)
Eli tässä vielä tuo "oikeaoppinen ratkaisu":
<?php function filter_text($data){ if ( get_magic_quotes_gpc() == 1 ) //poistetaan magic quotesit ja ajetaan funktio mysql:n oman funktion läpi return mysql_real_escape_string(stripslashes($data)); else return mysql_real_escape_string($data); } ?>
Hmm... ok, kiitti. :)
Ihmetyttää vain, että miksi ihmeessä PHP:n vakiofunktioihin ei voi kuulua tuollaista "oikeaa" tekstimuotoisen syötteen siivoajaa jos se kerran noin yksinkertaisesti onnistuu tehdä. :o
Muuten, eikö tuota $dataa kannata ajaa strip_tags()-funktion läpi? Sillähän saisi karsittua mahdollisia PHP-tageja mitä käyttäjä saattaa tunkea tekstikenttiin. :o
No kyllähän täällä putkassakin saa laittaa php-tageja ja html:ää viestin sekaan :) Tulostusvaiheessa ajat vain tekstin htmlentities()-funktion läpi.
"Ihmetyttää vain, että miksi ihmeessä PHP:n vakiofunktioihin ei voi kuulua tuollaista "oikeaa" tekstimuotoisen syötteen siivoajaa"
Kannattaa tutustua PDO->prepare() ja PDOStatement->bindParam() jolloin ei tuommosia asioita tarvitse miettiä vaan PHP/tietokanta hoitaa ne itse. Ja noita käytettäessä koodista tulee selkeempääkin.
Sekä PHP6:ssa tuo magic_quotes asetus on kokonaan poistettu joten se kannattaa ottaa jo nyt huomioon.
Ja tietokantaan data muotoilematta, sitten tulostusvaiheessa tagien poistot jne....
Hmm... huomasin juuri, että minulla ei jostain syystä tule oikein sellaiset arvot tietokannasta joissa on hipsuja ( ' ).
Tiedot kyllä menevät oikein kantaan, sillä siellä näkyy nyt "O'rlly", mutta kun haen tämän arvon ja tulostan ruudulle ilman mitään filtteröintejä, niin ruudulle tulee vain "O".
Lisäys
Testasin myös laittaa normaaleja lainausmerkkejä ( " ) kantaan ja ne näytti tulevan oikein kun hain tietoa ruudulle.
Lisäys 2.
Kenttään tulee näymmä tällainen arvo:
<input type='text' value='O"rlly O'rlly'>
Eli tietokannasta tulee arvo täysin oikein, mutta se katkaisee arvon tulostamisen tuohon ' -merkkiin. :/
Lisäys 2.
Heh, löysinpähän ratkaisun! :]
Piti lisätä htmlentities() -funktioon lisäparametri:
htmlentities($str, ENT_QUOTES)
Se ei oletuksena näymmä käsittele heittomerkkejä, ainoastaan lainausmerkit.
htmlentities
Aihe on jo aika vanha, joten et voi enää vastata siihen.