Czym jest SQL Injection?
Z języka angielskiego jest to wstrzyknięcie kodu SQL do programu/skryptu/aplikacji. Program, skrypt, strona, które nie są odporne na ataki SQL Injection stwarzają ogromne ryzko dla użytkownika oraz dla samego systemu. Poprzez SQL Injection atakujący może uzyskać dostęp do naszej bazy danych, modyfikować ją, a nawet usunąć.
Jak wygląda atak SQL injection?
Prześledzmy poniższy kod PHP
$name = $_GET['name']; mysql_query("SELECT * FROM `uzytkownicy` WHERE `imie` = $name");
parametr $name pobierany jest bezpośrednio z adresu URL, programista zakłada, że użytkownik zawsze wprowadzi imię. Jest to błędne podejście! Co w przypadku gdy ktoś wprowadzi poniższy ciąg znaków?
'Robert'; DELETE * FROM uzytkownicy
Wtedy zapytanie MySQL będzie wyglądało tak:
SELECT * FROM `uzytkownicy` WHERE `imie` = 'Robert'; DELETE * FROM uzytkownicy
Czyli po wykonaniu zapytania SELECT zostaną usunięte wszystkie rekordy z tabeli uzytkownicy!
Jak się zabezpieczyć przed SQL Injection?
Istnieje kilka zasad, które należy spełnić, aby uchronić się przed SQL Injection.
- Używaj walidacji danych – jeżeli oczekujemy liczby to sprawdź czy dana jest liczbą(is_numeric()), jeśli oczekujesz imienia to sprawdź czy dany ciąg znaków zawiera tylko i wyłącznie litery(preg_match())
- Używaj „prepared statements” czyli parametryzowanych zapytań do bazy
- Obcinaj dane, które są nieistotne
- Ustaw mniejsze przywileje dla użytkownika bazy danych, który korzysta ze strony. Nie możesz ustawić mu praw administratora, gdyż podczas ataku sql injection uzyskuje on dostęp do wszystkich baz mysql na serwerze!
- Nie wyświetlaj błędów w aplikacji produkcyjnej! Bardzo ważny punkt, ponieważ gdy wyświetlasz błędy atakujący może dostosować swój atak i sprawdzać efekty. Oczywiście istnieje jeszcze tak zwane Blind SQL Injection, ale jest to o wiele trudniejszy atak.
- Prowadź logi wszelkich prób ataków i wyciągaj wnioski, konsekwencje nie pozwól by atakujący pozostał bezkarny.
Jak zabezpieczyć powyższe zapytanie mysql przed atakiem SQL Injection?
Po pierwsze należy zmienić biblioteke używającą mysql z mysql_* na mysqli lub PDO. Funkcje z rodziny mysql_* są uważane jako przestarzałe na oficjalnej stronie php.net
Następnie należy użyć „prepared statements”. Poniżej przedstawiam w pełni bezpieczny kod.
<?php $name = $_GET['name']; //1 walidacja if(preg_match('#[a-zA-Z]+#', $name) == false) die('nieprawidlowe dane wejsciowe'); //1. Pierwszy sposób - użycie PDO $dbc= new PDO('mysql:dbname=baza;host=127.0.0.1;charset=utf8', 'user', 'pass'); $dbc->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $dbc->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt = $dbc->prepare('SELECT * FROM `uzytkownicy` WHERE `imie` = :name'); $result = $stmt->execute(array('name' => $name)); //2. Drugi sposób - użycie MySQLi $mysqli = new mysqli("server", "username", "password", "database_name"); $stmt = $mysqli->prepare("SELECT * FROM `uzytkownicy` WHERE `imie` = ?"); $stmt->bind_param("s", $name); $stmt->execute(); $stmt->close(); $mysqli->close(); ?>
W swoich aplikacjach pamiętaj o tym, gdyż SQL Injection jest jednym z najczęściej przeprowadzanych ataków.
Zostaw komentarz