Preorder drugiego tomu książki sekuraka: Wprowadzenie do bezpieczeństwa IT. -15% z kodem: sekurak-book
Czym jest SQL injection?
Z tekstu dowiesz się
- Czym jest podatność SQL injection
- Jakie są możliwe skutki jej wykorzystania
- W jaki sposób uzyskiwany jest nieautoryzowany dostęp do bazy danych z wykorzystaniem SQL injection
- Jakie są podstawowe metody ochrony przed atakami
Wstęp
Czym jest SQL injection?
To jedna z dość częstych i jednocześnie niebezpiecznych podatności w aplikacjach webowych (oraz niewebowych). Nie bez powodu SQL injection należy do pierwszej (A1) z dziesięciu kategorii błędów wymienianych w dokumencie OWASP Top Ten. Już sama nazwa wskazuje na rodzaj problemu – atakujący wstrzykuje do aplikacji (nieautoryzowany) fragment zapytania SQL. Wstrzyknięcie zazwyczaj możliwe jest z jednego powodu – braku odpowiedniego sprawdzenia (walidacji) parametru przekazanego przez użytkownika. Taki parametr, gdy mamy do czynienia z SQL injection, często przekazywany jest bezpośrednio do zapytania SQL.
Czym to może skutkować?
W zależności od sytuacji możemy mieć do czynienia z:
- nieautoryzowanym dostępem w trybie odczytu lub zapisu do całej bazy danych,
- możliwością ominięcia mechanizmu uwierzytelnienia,
- możliwością odczytania wybranych plików (system operacyjny, na którym pracuje baza danych),
- możliwością tworzenia plików w systemie operacyjnym, na którym pracuje baza,
- możliwością wykonania kodu w systemie operacyjnym (uprawnienia użytkownika, na którym pracuje baza lub web serwer – w przypadku aplikacji webowych).
Poniższe informacje podane są jedynie w celach edukacyjnych.
Ewentualne testy z wykorzystaniem zamieszczonych tu informacji należy realizować jedynie na systemach, których bezpieczeństwo możemy oficjalnie sprawdzać.
Przykład praktyczny
Zobaczmy, jaka jest istota tej podatności na przykładzie prostej aplikacji napisanej w języku PHP, komunikującej się z bazą danych MySQL z wyświetleniem szczegółów newsa (przy okazji zaznaczam, że podatność nie jest ograniczona tylko do języka PHP czy MySQL).
W normalnym użyciu wyświetlenie newsa odbywa się poprzez odwołanie do URL-a: http://192.168.0.105/news_detail.php?id=1&action=view
Aplikacja wykonuje wtedy następujące czynności (kliknij dwa razy, aby powiększyć):
Co się jednak stanie w przypadku, gdy zmodyfikujemy wartość zmiennej id?
Na przykład w ten sposób:
http://192.168.0.105/news_detail.php?id=-1 union select version(),2–&action=view.
Zobaczmy:
Okazuje się, że w tym przypadku można było odczytać wynik funkcji bazodanowej version()!
Na podobnej zasadzie można tu również odczytać wybrane pliki z filesystemu:
Analogicznie możliwe jest również pobranie danych z zupełnie innej tabeli niż oryginalna 'news’.
Na przykład można pobrać login oraz hasła z tabeli 'users’:
Jak z kolei będzie wyglądać sytuacja w przypadku, gdy nie mamy do czynienia ze zmienną liczbową tylko ze stringiem?
Zobaczmy na przykładzie formularza logowania:
W tym przypadku udało się zalogować na użytkownika 'admin’ bez znajomości jego hasła.
W jaki sposób można zalogować się na innego użytkownika? Patrząc na diagram powyżej, należałoby wybrać nie pierwszego z brzegu, a kolejnego użytkownika z tabeli 'users’:
Ochrona
Nawet w tak skrótowym tekście warto poświęcić kilka słów ochronie przed SQL injection.
W jaki sposób się ochronić?
Mówiąc w dużym skrócie – w odpowiedni sposób weryfikować zmienne przekazywane do użytkownika do aplikacji.
- W pierwszym omówionym przypadku (zmienna id) wystarczy sprawdzać czy przekazana zmienna jest liczbą.
- W przypadku z mechanizmem logowania sytuacja jest trochę bardziej skomplikowana – tutaj należy uniemożliwić zamknięcie przez atakującego zmiennej tekstowej znakiem ’ (np. używając funkcji mysql_real_escape_string(), choć sugerowaną metodą jest stosowanie zapytań parametryzowanych (update: np. w najnowszej wersji PHP – 5.5.0 mysql_real_escape_string() deprecated i prawdopodobnie w przyszłych wersjach nie będzie obsługiwana))
— michal.sajdak<at>securitum.pl
moglibyście przy okazji zrobić jakiś poradnik do bt :D
pewnie kiedyś ;) Na razie kilka rzeczy o webie – bo ostatnio coś czytelnicy narzekali że nie ma nic web-u ;)
–ms
Albo używać funkcji i procedur do pobierania/modyfikacji informacji w bazie. Jak parametr będzie miał coś niepokojącego w sobie to i tak będzie dalej parametrem, czyli np. stringiem i tak zostanie potraktowany. Najwyżej funkcja wywali błąd, że został przekazany błędny typ.
Oczywiście, parametry powinny i tak być w jakiś sposób filtrowane.
Zgadza się (choć z tymi funkcjami to uwaga – bo jeśli tam jest gdzieś dynamiczne zapytanie to może być SQLi). Trochę będzie o tym w kolejnych odcinkach o SQLi – bo takie planuję :) M.in. też przykłady źle przygotowanych zapytań parametryzowanych.
–ms
Moglibyście jeszcze wspomnieć że poza samą aplikacją korzystającą z bazy danych należy zabezpieczyć też samą bazę. Stworzenie odpowiednich perspektyw i użytkowników z bardzo ograniczonymi prawami może sprawić że sam fakt istnienia SQL injection w aplikacji nie będzie zagrożeniem.
@Oskar – zgadza się. Choć tekst raczej jest wprowadzający w temat :) Postaram się podać więcej przykładów w kolejnych tekstach o SQLi.
–ms
BTW, polecam niezależne rekomendacje hardeningowe do DB: https://benchmarks.cisecurity.org/downloads/multiform/index.cfm
–ms
Moglibyście opisać jak się chronić przed SQL Injection od strony serwerowej? W necie jest już mnóstwo artykułów o tym jak tworzyć bezpieczne aplikacje, ale wielu programistów chyba i tak tego nie czyta… Brakuje natomiast artów (zwłaszcza w języku polskim) poruszających takie kwestie jak na przykład używanie mod_security dla serwerów webowych.
Jest u nas w planach (tzn. pisze się już :) seria tekstów generalnie o tematyce monitoringu bezpieczeństwa. OSSEC, snort, może i na mod_security wystarczy trochę czasu, choć przyznam że mamy trochę ograniczone moce przerobowe ;-)
PS. Gdyby ktoś przypadkiem chciał przygotować tekst w jednym z ww. tematów to proszę o maila -> sekurak@sekurak.pl
-ms
Postaram sie cos przygotowac o modsecu:-) niech ten wpis bedzie moim motywatorem, pozdr0!
To czekamy na arta :-)
-ms
Taki kod jest zupełnie bezpieczny dla danych
$sql = „SELECT title, body FROM news WHERE id = $_GET[’id’]”;
walnie takim soczystym parse errorem że nikt nie haknie sajta ;)
@ixdude: jak to mawiają – u mnie działa ;-)
Info o deprecjacji – tak, dzięki, zrobiłem mały update w arcie. Choć ta wersja php-a ma dosłownie kilka dni, więc i stare funkcje będę jeszcze dłuuugo. Też jak najbardziej zapytania parametryzowane to preferowana metoda ochrony (nie tylko w PHP)
-ms
Co do metod zabezpieczania to funkcje z rozszerzenia mysql, zostały ostatecznie zdeprecjonowany (http://www.php.net/ChangeLog-5.php#5.5.0), tym samym zaleca się używanie filtrowania danych w inny sposób albo po prostu używania sparametryzowanych zapytań z mysqli czy PDO. Ogólnie fajny art.
Pozdrawiam.
Czemu mam kliknąć obrazek DWA RAZY, aby powiększyć? :(
To prawda – mało wygodne, dokładam to TODO.
-ms