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']);