SQL Injection (Sigurnost PHP aplikacija – 5. deo)

Ovo je četvrti u seriji članaka o sigurnosti PHP aplikacija. Pogledajte Sigurnost PHP aplikacija, Osnove sigurnosti, Validacija i filtriranje inputa i XSS

Dok XSS predstavlja indirektan napad na korisnike, SQL Injection predstavlja direktan napad na PHP aplikaciju, odnosno na bazu podataka. Cilj ovog napada je da se izmeni određeni SQL upit kako bi se izršile razne akcije, od dobijanja aletrantivnih podataka, do izmene ili brisanja podataka iz baze podataka.
Napad SQL Injection-om se uglavnom vrši na skripte za proveru autentifikacije korisnika, odnosno prilikom provere korisničkog imena i lozinke, kako bi se SQL upit izmenio i uvek izvršio tako da uvek “dohvata” podatke o nekom korisniku. Sledeći primer demonstrira propust prilikom provere korisničkih podataka:

<?php
// podaci sa login forme
$username = $_POST['username'];
$password = $_POST['password'];

// provera podataka
$sql = "SELECT * FROM korisnici WHERE username = '$username' AND password = '$password'";
$result = mysql_query($sql);
if(mysql_num_rows($result) > 0) {
// korisnik je ulogovan...
}
?>

Ukoliko bi napadač u ovakav login formular umesto korisničkog imena i lozinke uneo sledeću vrednost:

a' OR '1' = '1

SQL upit koji bi se izvršio izgledao bi ovako:

SELECT * FROM korisnici WHERE username = 'a' OR '1'='1' AND password = 'a' OR '1'='1'

Ovakav upit bi sigurno vratio podatke o nekom korisniku, i u ovom konkretnom primeru omogućio bi korisniku da bude ulogovan. Dodavanjem još nekih uslova, na primer WHERE id = ‘1’ ili nekog drugog ID-a, postoji velika verovatnoća da će biti autorizovan kao administrator sistema.
Osim kod provere autentifikacije, može se iskoristiti i u druge zlonamerne svrhe, a jedan od njih je ubacivanje dodatnog upita koji može uništiti podatke ili neke druge zlonamerne akcije.
Sledeći primer demonstrira SQL injection u cilju izvršenja dodatnog upita:

// ubacivanje dodatnog upita
$name = "Pera'; DELETE FROM korisnici”;
mysql_query("SELECT * FROM korisnici WHERE name='$name'");

Izvšenje više upita odjednom nije podržano u mysql_query() funkciji, ali drugi drajveri, npr za PostgreSQL ili SQLite, to dozvoljavaju, pa tako izvšenje ovakvog koda predstavlja ozbiljan sigurnosni propust.

Zaštita

Kao što je već spominjano u ranijim glavama, filtriranje inputa može sprečiti većinu sigurnosnih problema i obavezna je stavka sigurne aplikacije. Ukoliko bi filtrirali podatke tako da korisniku zabranimo unos specijalnih karaktera specifičnih za SQL upite, na primer apostrofe, i za lozinke možemo da koristimo jednosmerne enkripcije, na primer md5, sigurno bi povećali sigurnost. Međutim,postoje i druge metode za sprečavanje napada, a da dozvolimo sve karaktere:
• Escape inputa – mysql_real_escape_string()
• Pripremljeni izrazi

mysql_real_escape_string()

Ova funkcija pripada mysql drajveru, ali je poseduje i mysqli drajver (mysqli_real_escape_string) i osigurava da će svi specijalni karakteri biti pravilno eskejpovani, odnosno da se pri građenju upita i dalje ponašaju kao sastavni deo tog stringa i nikako ne iskoriste u izmeni upita. Ova funkcija je “best practice” i mora se izvršiti nad svim promenjivima koji grade upit.

$username = mysql_real_escape_string($_POST['username']);

Upit za gore navedeni primer nakon eskejpovanja-a promenjivih izgleda ovako:

SELECT * FROM korisnici WHERE username = 'a\' OR \'1\'=\'1' AND password = 'a\' OR \'1\'=\'1'

i zaštićen je od SQL injection napada. Pošto ove funkcije za eskejpovanje pripadaju drajveru za rad sa bazom podataka, sve kose crte “\” neće biti unete sa ostalim podacima u bazu, što nije slučaj u korišćenju addslashes funkcije.
Napomena: Pretpostavka je da je isključen magic_quotes_gpc, u suprotom se podaci moraju normalizovati, pa tek onda eskejpovati. Normalizacija podataka je objašnjena ranije.

Pripremljeni izrazi (Prepared statements)

Pripremljeni izrazi nisu tolika velika novost, ali mnogi programeri početnici izbegavaju da ih koriste, a verovatno je to zbog slabog razumevanja načina na koji rade. Pre svega, treba napomenuti da pripremljeni izrazi ne mogu da se koriste u starim verzijama drajvera, kao što je standaradni mysql. Takoreći, mysql drajver je starijeg datuma i njegov dalji razvoj je odavno obustavljen. Čak je i preporuka PHP konzorcijuma da se on potpuno izbaci iz korišćenja i da se koriste drajveri kao što su MySQLi i PDO. Ova dva drajvera su dosta brži i poseduju dosta sigurnosnih karakteristika.
Priprema izraza, odnosno njegovo građenje se odvija na MySQL serveru, pa stoga ne postoji mogućnost same izmene upita u php aplikaciji, a zbog načina na koji radi, ni na serveru. Prilikom pisanja upita, umesto promenjivih vrednosti koriste se operater “?”, a promenjive se šalju posebnom funkcijom, onim redosledom kakvim se ubacuju u upit.
Sledeći kôd opisuje rad MySQLi drajvera i pripremljenih izraza:

<?php
$username = $_POST['username'];
$password = $_POST['password'];

// Konekcija sa MySQL bazom
$mysqli = new mysqli('localhost', 'user', 'password', 'world');

$stmt = $mysqli->prepare("SELECT * FROM korisnici WHERE username = ? AND password = ? LIMIT 1");
// Vrednosti promenjivih se šalju na u upit
$stmt->bind_param('ss', $username, $password);

// izvršavanje upita
$stmt->execute();

if($stmt->affected_rows > 0) {
// korisnik je ulogovan
}

//...

// zatvaranje izraza i upita
$stmt->close();
?>

Više o MySQLi drajveru i njegovim funkcionalnostima možete saznati na adresi:
http://php.net/manual/en/book.mysqli.php

3 Comments

  1. Ah da, čuveni little bobby tables… 🙂

    http://xkcd.com/327/

  2. E super je ovo! Razmisli da se povuku podaci o username i passwordu korisnika i proveri u PHP kodu da li su isti stringovi. Ako su isti, onda je to to, ako nije ko ga jebe! 🙂

  3. Da ne skrenem puno s teme, ali i bez direktnog napada na SQL (pošto se baza nalazi na drugom disku), hakeri koristeći bilo koji crv mogu proizvesti isti efekat. Najčešće ako se uploaduju skripte otvorenog koda i već zaražene virusom, zaraze čitav hosting prostor te je lek opšte poznat – ili keš lova za čišćenje ili brisanje naloga. Pošto je sve više ovakvih napada, a biće ih mnogo, pozdravljam Vas, i vaš članak o ovoj problematici.