SQL és XSS injekció elleni védelem PHP-ban (htmlspecialchars, real_escape_string és előkészített utasítások használata)
Ha lehetőséget biztosítunk a felhasználóknak, hogy adatot adjanak meg a weboldalunkon (például jelszót írjanak be, vagy kommenteljenek), akkor mindenképp gondoskodnunk kell az SQL és az XSS injekció elleni védelemről. A PHP-ban szerencsére vannak lehetőségeink, amelyek segítenek biztonságossá tenni a weboldalunkat. Ezen a lehetőségek között szerepel a „htmlspecialchars„, a „real_escape_string„, illetve az előkészített utasítások használata.
Mi az az SQL és XSS injekciós támadás?
Maga a kódinjektálás azt jelenti, hogy egy adatbevitelre szolgáló helyen, valamilyen futtatható kódot helyeznek el, melynek célja, hogy hozzáférést szerezzen a weboldal fölött, vagy valamilyen olyan műveletet hajtson végre, amelyhez alapvetően nem lenne hozzáférése. Az injekciós támadás az egyik leggyakoribb támadási módszer a weboldalak ellen.
Az SQL injekciós támadások során általában HTML űrlapok bevitelimezőibe SQL utasításokat csempésznek, melyek segítségével képesek lehetnek törölni teljes adatbázistáblákat, illetve adatbázisokat.
Egy XSS injekciós támadás esetében a rosszindulatú támadó egy olyan kódot helyez el a forráskódba, amelyet ezt követően a többi felhasználó is látni fog. A legszörnyűbb az egészben, hogy egy átlagos felhasználónak nagyon nehéz rájönnie, hogy nem az oldal eredeti változatát, hanem a megfertőzött verzióját látja.
SQL és XSS injekciós támadás elleni védelem
A PHP nyelv több függvényt kínál, mely arra szolgál, hogy az űrlapbeviteli mezőkben található rosszindulatú kódokat eltávolítsa, de ezek közül kettő van, amelyek használata elengedhetetlen.
Fontos, hogy ezeket a függvényeket még az adatbázisba való adatfeltöltés előtt futtassuk a felhasználók által megadott szövegeken.
real_escape_string() használata SQL injekciós támadás elleni védekezéshez
Legelőször vizsgáljuk meg a „real_escape_string()” függvényt, mely elhagyja a karakterlánc speciális karaktereit az SQL utasításokból.
Szintaxis
KAPCSOLAT->real_escape_string(SQL.UTASÍTÁS); // objektumorientált megoldás
// vagy
mysqli_real_escape_string(KAPCSOLAT, SQL.UTASÍTÁS); // procedurálisan
Code language: PHP (php)
Természetesen itt is lehetőségünk van objektumorientáltan vagy procedurálisan megvalósítani az SQL injekciós támadás elleni védelmet.
Példa real_escape_string() használatára PHP-ban
PHP kód
<?php
// adatok felvétele a kapcsolathoz
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "test";
$conn = new mysqli($servername, $username, $password, $dbname); // kapcsolat létrehozása
$ertek1="Python'Java"; // itt nem használunk real_escape_string-et
$ertek2=$conn->real_escape_string("Python'Java"); //itt használunk real_escape_string-et
// real_escape_string NÉLKÜL
if (!$conn->query("INSERT INTO programnyelvek (nev) VALUES ('$ertek1')")) {
echo "A rekord hozzáadása nem sikerült: $ertek1";
} else {
echo "Sikeres rekordhozzáadás: $ertek1";
}
echo "<br>";
// real_escape_string SEGÍTSÉGÉVEL
if (!$conn->query("INSERT INTO programnyelvek (nev) VALUES ('$ertek2')")) {
echo "A rekord hozzáadása nem sikerült: $ertek2";
} else {
echo "Sikeres rekordhozzáadás: $ertek2";
}
// kapcsolat lezárása
$conn->close();
?>
Code language: HTML, XML (xml)
Eredmény
A rekord hozzáadása nem sikerült: Python’Java
Sikeres rekordhozzáadás: Python\’Java
A fenti példa csak egy kis egyszerű szemléltetés, hogy míg a PHP a „Python’Java” szöveget nem engedi át, mert fennakad az aposztróf miatt, addig a „real_escape_string” függvény futtatása után gond nélkül lefut.
htmlspecialchars() használata XSS injekciós támadás elleni védekezéshez
A speciális karaktereket HTML entitásokká alakítja az alábbi táblázat szerint.
Karakter | Átalakított érték |
---|---|
& | $amp; |
„ | $quot; |
‘ | $#039; |
< | $lt; |
> | $gt; |
Szintaktika
htmlspecialchars(SZÖVEG);
Példa htmlspecialchars() függvény használatára PHP-ban
PHP kód
<?php
$szoveg = "Szöveg <br> HTML taggel.<br>";
echo $szoveg;
echo htmlspecialchars($szoveg);
?>
Code language: HTML, XML (xml)
Eredmény
Szöveg
HTML taggel.
Szöveg <br> HTML taggel.<br>
Láthatjuk az első echo-nál, hogy amikor nem használtunk „htmlspecialchars”-t, akkor a kiíratás során a PHP figyelembe vette a HTML tag-eket is, jelen esetben a <br>-eket, de a „htmlspecialchars” segítségével már azt is csak egyszerű szövegnek tekintette.
Előkészített utasítások
Az előkészített utasításokat (angolul prepared statements) a legegyszerűbben úgy lehet leírni, hogy van egy előre elkészített utasításunk, amelybe vannak hiányzó paraméterek, amelyeket a PHP biztonságosan feltölt a felhasználó által átadott értékekkel.
Szintaxis
$VÁLTOZÓ = $KAPCSOLAT->prepare("UTASÍTÁS");
Code language: PHP (php)
Legelőször szükségünk van egy utasításra, amelybe kérdőjeleket („?”) kell tennünk azokra a helyekre, amiket utólag egyszerűen és gyorsan szeretnénk feltölteni.
$VÁLTOZÓ->bind_param("TÍPUS(OK)", BEILLESZTENDŐ.VÁLTOZÓK);
Code language: PHP (php)
Majd a „bind_param()” segítségével meg kell adnunk, hogy milyen típusú adatokat várunk a kérdőjelek helyére, illetve azt, hogy mely változókba fogjuk tárolni a kérdőjelek helyére szánt értékeket.
A típusokat az alábbi betűkkel kell jelölni:
- i – integer
- d – double
- s – string
- b – BLOB
$BEILLESZTENDŐ.VÁLTOZÓ = ÉRTÉK;
Code language: PHP (php)
Ezután a beillesztendő változókat feltöltjük értékekkel.
$KAPCSOLAT->execute();
Code language: PHP (php)
Majd szimplán a kapcsolatot végrehajtjuk az utasítást.
Lehet, hogy ez így szintaxis alapján leírva bonyolultnak tűnik, de valójában nem az, egy példán keresztül látni fogjátok, hogy mennyire is egyszerű ez.
Példa előkészített utasítások használatára PHP-ban
Adatbázis
nev | megjelenesi_ev |
---|---|
PHP kód
<?php
// adatok felvétele a kapcsolathoz
$servername = "localhost";
$username = "felhasznalo";
$password = "jelszo";
$dbname = "adatbazis";
$conn = new mysqli($servername, $username, $password, $dbname); // kapcsolat létrehozása
$sql = $conn->prepare("INSERT INTO programnyelvek (nev, megjelenesi_ev) VALUES (?, ?)"); // elkészítjük az utasítást, amelybe a kérdőjelek helyére várjuk az értékeket
$sql->bind_param("ss", $nev, $megjelenesi_ev); // két string-et várunk, az első kérdőjel helyére a $nev változó tartalma fog menni, a második változó helyére a $megjelenesi_ev változó tartalma
$nev = "PHP"; // $nev változóba felvesszük a "PHP" értéket
$megjelenesi_ev = "1995-06-08"; // a $megjelenesi_ev változóba felvesszük az adatot
$sql->execute(); // a felvett változókkal futtatjuk az előkészített utasításokat
$nev = "JavaScipt"; // $nev változóba felvesszük a "JavaScript" értéket
$megjelenesi_ev = "1995-12-04"; // a $megjelenesi_ev változóba felvesszük az adatot
$sql->execute(); // a felvett változókkal futtatjuk az előkészített utasításokat
// kapcsolat lezárása
$conn->close();
?>
Code language: HTML, XML (xml)
Eredmény
Adatbázis
nev | megjelenesi_ev |
---|---|
PHP | 1995-06-08 |
JavaScript | 1995-12-04 |
Először elkészítettük az „$sql” változóba az előkészített utasításunkat, ahol kérdőjellel jelöltük, hogy mely adatokat nem szeretnénk megadni jelenleg, hanem csak utólag. A kérdőjelek helyére fogjuk betölteni a később felvett adatokat. A „bind_param()”-ban rögtön két „s”-t írunk, ezzel jelölve, hogy két szövegtípusú (string) értéket várunk, majd megadjuk, hogy az első értéket a „$nev” változóba, a másodikat a „$megjelenesi_ev” változóban fogjuk tárolni. Ezután felvesszük a két említett változót, melynek értékeket adunk. Ezek lesznek behelyettesítve a kérdőjelek helyére. Ezt követően az „execute()” parancs segítségével végrehajtjuk az adatok adatbázisba való feltöltését. A további adatok feltöltéséhez már csak az utolsó három sort kell megismételni, azaz adatokat kell adnunk a változóknak, majd végre kell hajtanunk a feltöltést az „execute()” segítségével.