PHP/SQL Injection
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']);