PHP/SQL Injection

Z Wikibooks, biblioteki wolnych podręczników.
< PHP
Poprzedni rozdział: Operacje na plikach
Następny rozdział: Szyfrowanie

SQL Injection[edytuj]

Atak typu SQL Injection polega na takiej zmianie jednego lub kilku parametrów zapytania (query) wysyłanego do bazy danych typu SQL, że polecenie to staje się niezgodne z zamierzeniem autora skryptu.

Załóżmy, że mamy stronę, która wyświetla dane klientów naszej firmy. Użytkownik po wejściu na stronę listaklientow.php otrzymuje listę klientów wyświetlająca wszystkich klientów firmy, którzy w bazie danych w kolumnie wyswietl mają wartość 1. Strona daneklienta.php, do której prowadzą łącza ze strony listaklientow.php wyświetla natomiast dane klienta dostarczone za pomocą zmiennej klient, a więc np. daneklienta.php?klient=Kowalski wyświetla dane dowolnego (ważne dla dalszej części przykładu) klienta o ID Kowalski. Co jednak, kiedy dane jakiegoś klienta nie powinny być oglądane przez niepowołane osoby? Administrator strony ustawia co prawda wartość 1 w kolumnie wyswietl bazy danych tylko dla określonych klientów, ale ktoś wpada na pomysł zrobienia czegoś takiego: daneklienta.php?klient=Tajny, gdzie klient o ID Tajny to klient, do którego profilu link nie jest wyświetlany przez plik listaklientow.php, jednak skrypt wyświetla dane klienta o dowolnym ID! Wtedy już mamy problem. Baza danych dostaje rozkaz wyświetlenia informacji dla ID Tajny, a skrypt jej tego nie zabrania. Właśnie wtedy mamy do czynienia z prostym SQL Injection.

Groźniejszym typem SQL Injection jest wypadek, w którym wspomniany ktoś (potencjalny cracker) wyśle w zmiennej klient instrukcję:

'; TRUNCATE TABLE klienci

I problem gotowy. Cała tabela klienci jest czyszczona, ponieważ zapytanie SQL wyglądało w sposób:

mysql_query("SELECT zamowienia FROM klienci WHERE id='". $_GET['id'] ."'");

Jak widać, apostrof (') jest zamykany i wydawane jest nowe, niebezpieczne polecenie SQL.

Jednakże najgroźniejsza sytuacja jest w formularzach logowania. Wystarczy, że cracker poda login:

' or 1=1 --

i ma dostęp do konta administratora.

Zabezpieczanie się przed SQL Injection[edytuj]

Zabezpieczyć się przed atakiem typu SQL Injection można bardzo łatwo - wystarczy przefiltrować cudzysłowy oraz apostrofy z parametru wysyłanego do zapytania SQL. Wiele opcji hostingowych ma domyślnie wyłączony znienawidzony przez programistów parametr magic_quotes_gpc (dla serwerów Apache), która dodaje znak \ przed każdym potencjalnie niebezpiecznym znakiem parametru. Używając PDO, wystarczy używać funkcji prepare() i ustawiać zmienne. W starych funkcjach mysql_* można dokonać tego korzystając z funkcji mysql_escape_string(), która robi to samo, co wspomniane magic_quotes_gpc, np.

$id = mysql_escape_string($_GET['id']);

Jeśli parametr, który chcemy pobrać jest np liczbą, i chcemy żeby był wartością tylko tego typu możemy zastosować rzutowanie albo użyć funkcji intval, np.

$id = (int)$_GET["id"]; //Wersja z rzutowaniem
$id = intval($_GET["id"]); //Wersja z intval

Spowoduje to, że jeśli wpiszemy coś innego niż liczbę zostanie ona zamieniona na 0

Dodatkowe informacje[edytuj]

Wartym odnotowana jest jeszcze przypadek, w którym mamy do czynienia z serwerami z włączonym magic_quotes_gpc(). Jeśli nie chcemy/nie możemy go wyłączyć, możemy skorzystać z funkcji stripslashes(), która działa odwrotnie do funkcji mysql_escape_string():

$id = stripslashes($_GET['id']);