MySQL - i SQL Injection
Jeśli weźmiesz dane wejściowe użytkownika za pośrednictwem strony internetowej i wstawisz je do bazy danych MySQL, istnieje szansa, że pozostawiłeś się szeroko otwarty na problem bezpieczeństwa znany jako SQL Injection. Z tego rozdziału dowiesz się, jak temu zapobiec i jak zabezpieczyć swoje skrypty i instrukcje MySQL.
SQL Injection zwykle występuje, gdy poprosisz użytkownika o wprowadzenie danych, na przykład jego imię i nazwisko, a zamiast nazwy podają ci instrukcję MySQL, którą nieświadomie uruchomisz w swojej bazie danych.
Nigdy nie ufaj danym dostarczonym przez użytkownika, przetwarzaj te dane dopiero po walidacji; z reguły odbywa się to poprzez dopasowywanie wzorców. W poniższym przykładzie nazwa użytkownika jest ograniczona do znaków alfanumerycznych i podkreślenia oraz do długości od 8 do 20 znaków - zmodyfikuj te zasady w razie potrzeby.
if (preg_match("/^\w{8,20}$/", $_GET['username'], $matches)) {
$result = mysql_query("SELECT * FROM users WHERE username = $matches[0]");
} else {
echo "username not accepted";
}
Aby zademonstrować ten problem, rozważ następujący fragment.
// supposed input
$name = "Qadir'; DELETE FROM users;";
mysql_query("SELECT * FROM users WHERE name = '{$name}'");
Wywołanie funkcji ma na celu pobranie rekordu z tabeli użytkowników, gdzie kolumna name odpowiada nazwie podanej przez użytkownika. W normalnych okolicznościach $ nazwa zawierałaby tylko znaki alfanumeryczne i być może spacje. Ale tutaj, dołączając zupełnie nowe zapytanie do$name, wezwanie do bazy danych zamienia się w katastrofę. Wstrzyknięte zapytanie DELETE usuwa wszystkie rekordy od użytkowników.
Na szczęście, jeśli używasz MySQL, rozszerzenie mysql_query()funkcja nie zezwala na układanie zapytań w stos lub wykonywanie wielu zapytań w jednym wywołaniu funkcji. Jeśli spróbujesz zestawić zapytania, wywołanie nie powiedzie się.
Jednak inne rozszerzenia baz danych PHP, takie jak SQLite i PostgreSQL, szczęśliwie wykonuj zapytania skumulowane, wykonując wszystkie zapytania dostarczone w jednym ciągu i tworząc poważny problem z bezpieczeństwem.
Zapobieganie iniekcji SQL
Możesz inteligentnie obsługiwać wszystkie znaki ucieczki w językach skryptowych, takich jak PERL i PHP. Rozszerzenie MySQL dla PHP zapewnia tę funkcjęmysql_real_escape_string() aby uniknąć znaków wejściowych, które są specjalne dla MySQL.
if (get_magic_quotes_gpc()) {
$name = stripslashes($name);
}
$name = mysql_real_escape_string($name);
mysql_query("SELECT * FROM users WHERE name = '{$name}'");
LIKE Quandary
Aby rozwiązać problem LIKE, niestandardowy mechanizm zmiany znaczenia musi konwertować dostarczone przez użytkownika znaki% i _ na literały. Posługiwać sięaddcslashes(), funkcja, która pozwala określić zakres znaków do zmiany znaczenia.
$sub = addcslashes(mysql_real_escape_string("%something_"), "%_");
// $sub == \%something\_
mysql_query("SELECT * FROM messages WHERE subject LIKE '{$sub}%'");