Blog

Głodny wiedzy? Na evoBlogu czekają artykuły napisane przez naszych specjalistów.

Ataki typu SQL Injection – czym są i jak im zapobiegać

Ataki SQL Injection znane są od wielu lat. O dawna wiadomo także, jak im zapobiegać. Mogłoby się wydawać, że nie powinny obecnie stanowić większego problemu. Jednak badania pokazują, że wciąż tego typu ataki są wykorzystywane do forsowania zabezpieczeń aplikacji. Odkrywane są również nowe podatności związane z tym zagrożeniem.

Według OWASP Top Ten, ataki typu Injection plasują się na trzecim mijescu spośród największych zagrożeń [1]. Wzrasta także liczba znanych podatności z tym związanych [2].

Przy tworzeniu aplikacji kluczowe jest poświęcenie odpowiednio dużo uwagi kwestiom bezpieczeństwa. Jest to istotne już od samego początku projektu, podczas tworzenia architektury całego rozwiązania. Tym bardziej, że omawiane ataki stanowią poważne zagrożenie mogące nieść za sobą fatalne skutki. W ten sposób można uzyskać nieautoryzowany dostęp do aplikacji, pobrać wszystkie dane z bazy, a nawet całkowicie przejąć kontrolę nad systemem. Przyjrzyjmy się zatem w jaki sposób przeprowadzane są tego typu ataki, jak wykrywać luki w zabezpieczeniach i w jaki sposób zabezpieczać aplikacje przed tymi zagrożeniami.

Źródło: https://xkcd.com/327

Czym jest SQL Injection?

SQL Injection jest wstawieniem, za pomocą danych wejściowych, w pełni poprawnego fragmentu kodu SQL do logiki aplikacji, aby wymusić pożądaną odpowiedź z bazy. Jeśli dane wejściowe nie zostaną prawidłowo oczyszczone, wówczas może dojść do wykonania, przez silnik bazy danych, wstrzykniętego kodu.

Przez dane wejściowe najczęściej rozumiemy parametry przekazywane za pomocą metod GET lub POST (np. z formularza). Jednak mogą być do tego celu wykorzystywane także np. nagłówki HTTP Cookie lub HTTP User-Agent (w zależności od aplikacji i podatności).

Załóżmy, że mamy aplikację z następującym adresem URL:

Adres ten niech zwraca listę produktów dla wskazanej kategorii wykorzystując następujące zapytanie SQL:

Więc w przypadku powyższego adresu URL skutkuje to następującym zapytaniem:

Powyższe zapytanie zwraca listę produktów dla kategorii, której id wynosi 1 oraz które spełniają warunek active = 1 , co ogranicza produkty tylko do tych, które są oznaczone, jako aktywne.


Jeśli jednak zmodyfikujemy powyższy adres URL w następujący sposób:

Poskutkuje to wykonaniem następującego zapytania SQL (w przypadku, gdy dane wejściowe nie zostaną prawidłowo oczyszczone):

Ponieważ oznacza komentarz w SQL, to całość zapytania za komentarzem nie zostanie wykonana. W związku z tym, tak spreparowane zapytanie zwróci wszystkie produkty dla kategorii 1 (niezależnie od wartości active ).

Zmodyfikujmy ponownie nasz URL:

Po przekazaniu parametrów do zapytania SQL otrzymamy:

Ponieważ warunek category_id = 1 OR 1=1 zwraca zawsze true , więc całe zapytanie zwróci wszystkie produkty, niezależnie od kategorii i wartości active .

To są najprostsze przykłady wykorzystania SQL Injection, pokazują jednak w jaki sposób w niezabezpieczonej aplikacji można pobrać dane, które nie powinny być dostępne. W rzeczywistości wykorzystywanych jest wiele różnych technik pozwalających na uzyskanie nieautoryzowanego dostępu do aplikacji lub danych.

Nieautoryzowany dostęp do aplikacji

Powszechnym wykorzystaniem SQL Injection jest uzyskanie nieautoryzowanego dostępu do aplikacji. Jest to typowa cecha bardzo często opisywana w literaturze dotyczącej cyberbezpieczeństwa.

Załóżmy, że do uwierzytelnienia wykorzystywane są dwa parametry emailpassword , które wprowadzane będą przez użytkownika w formularzu logowania i przesyłane metodą POST.

Załóżmy także, dla uproszczenia, że do uwierzytelniania użytkowników wykorzystywane jest następujące zapytanie SQL:

Oczywiście, jest to bardzo uproszczony scenariusz, a przy tym szczególnie niebezpieczny, bo nie zakłada szyfrowania hasła, jednak na potrzeby przykładu jest wystarczający. Co więcej, jak się za chwilę okaże, sam sposób przechowywania i porównywania hasła w tym przypadku traci na znaczeniu, bo atak SQL Injection zakłada nieznajomość hasła.

Jeżeli przesłane zostaną następujące wartości parametrów:

wówczas zapytanie wykonywane przez silnik bazy danych przyjmie następującą postać:

Jeżeli warunek w sekcji WHERE zostanie spełniony, to nastąpi uwierzytelnienie użytkownika.

Załóżmy jednak, że nie znamy hasła tego użytkownika. Zmodyfikujmy więc wartość przesyłanego parametru email w następujący sposób:

W takim przypadku zapytanie przesłane do bazy przyjmie następującą postać:

Zwróćmy uwagę, że wprowadzenie sekwencji spowoduje potraktowanie pozostałej części zapytania jako komentarz i hasło w ogóle nie będzie sprawdzane.


Atak SQL Injection może być przeprowadzony także wtedy, gdy nie znany jest nawet adres email użytkownika. Rozważmy przypadek, gdy jako parametr email prześlemy następującą wartość:

Wówczas zapytanie przesłane do bazy wyglądać będzie w taki sposób:

Powyższy warunek WHERE zawsze będzie spełniony i zapytanie zwróci wszystkie rekordy z tabeli users . W wielu przypadkach umożliwi to zalogowanie na konto pierwszego zwróconego użytkownika.

Chcesz sprawdzić bezpieczeństwo swojej aplikacji?

Systemy informatyczne wymagają stałego monitorowania i powinny podlegać okresowym kontrolom bezpieczeństwa IT

Taki atak niesie za sobą katastrofalne skutki, dając nieuprawnionej osobie dostęp do chronionych zasobów. Równocześnie, zabezpieczenie aplikacji przed wspomnianymi działaniami jest stosunkowo proste, dlatego tak ważne jest stosowanie odpowiednich technik wytwarzania oprogramowania i zabezpieczenie programu już na poziomie tworzenia jej architektury.

Operator UNION – pobieranie danych z innej tabeli

Do tej pory analizowaliśmy przykłady, gdy, poprzez odpowiednie wstrzyknięcie fragmentu SQL, modyfikowaliśmy zapytanie operując jednak na tabeli, która była w oryginalnym zapytaniu. SQL Injection umożliwia jednak pobranie danych także z innych tabel, co czyni ten rodzaj podatności jeszcze bardziej niebezpiecznym.

Do pobrania danych z innej tabeli wykorzystywany jest operator UNION . Operator ten umożliwia wykonanie dodatkowego zapytania SELECT , które jest dodawane do pierwotnego zapytania.

Powróćmy do naszego wcześniejszego przykładu, gdzie oryginalne zapytanie zwracało listę aktywnych produktów dla danej kategorii. Tylko przyjmijmy, dla uproszczenia, że zapytanie zwraca tylko dane z dwóch kolumn namedescription

Jeżeli zamiast id kategorii do powyższego zapytania wstawimy:

otrzymamy wówczas zapytanie:

W takim przypadku razem z nazwami i opisami produktów otrzymamy również adresy email użytkowników i ich hasła.
Nawet, jeżeli hasła są zahashowane z wykorzystaniem funkcji skrótów kryptograficznych (co jest standardem), to uzyskane hashe również mogą być wektorem ataku i także (w zależności od rodzaju funkcji skrótu) mogą doprowadzić do uzyskania haseł.

W naszym przykładzie przyjęliśmy jednak pewne uproszczenia. Po pierwsze, założyliśmy, że znamy liczbę kolumn w zapytaniu SELECT , a po drugie, założyliśmy, że znamy strukturę bazy danych, a przynajmniej wiemy o istnieniu tabeli users .

Nie jest to jednak większym problemem dla potencjalnego napastnika. Bez problemu, modyfikując zapytanie, można sprawdzić, jaka jest wymagana liczba kolumn w zapytaniu. Nazwę tabeli można odgadnąć w zależności od tego, jakie dane są poszukiwane. Co więcej, przy nieprawidłowo zabezpieczonej bazie danych, można, również za pomocą UNION , uzyskać wiedzę o zastosowanym silniku bazy danych. Na tej podstawie, wiedząc, jak w danym rodzaju bazy danych przechowywane są informacje o tabelach, można pobrać kompletny schemat bazy danych (także wykorzystując UNION ). Mając te informacje można pobrać całą bazę danych! Dlatego ten rodzaj ataku jest tak bardzo niebezpieczny.

W tym artykule skupiamy się wokół tego, jak istotne jest odpowiednie zabezpieczenie aplikacji przed atakami SQL Injection oraz jak wykrywać tego typu zagrożenia w tworzonych rozwiązaniach. Dlatego nie analizujemy dogłębnie wszystkich możliwości wykorzystania operatora UNION , a jedynie wskazujemy jak ważne jest przyjęcie właściwych standardów kodowania i na co zwracać uwagę podczas realizacji projektów.

Stacked queries – przejęcie kontroli

Ataki SQL Injection z wykorzystaniem techniki „Stacked queries” umożliwiają przejęcie kontroli nad bazą danych. Polega na dodaniu kolejnego zapytania do wcześniejszego. W tym przypadku wiele zależy od konkretnego silnika bazy danych, ponieważ nie każdy rodzaj bazy danych wspiera tego typu operacje.

W kontekście baz danych umożliwiających takie zapytania, wykorzystanie tej cechy, przy podatności aplikacji na ataki SQL Injection, może prowadzić do bardzo niebezpiecznych sytuacji.

Wracając do naszego przykładu z listą produktów, jeżeli jako wartość parametru określającego id kategorii zostanie przesłana następująca wartość:

wówczas zapytanie przybierze następującą postać:

W takim przypadku po zapytaniu SELECT zostanie wywołane zapytanie DELETE usuwające wszelkie rekordy z tabeli products .

Omawiana podatność może być wykorzystana także do zmiany danych – za pomocą zapytań typu UPDATE .

Szukasz wykonawcy, który jakość kodu stawia na pierwszym miejscu?

Zapraszamy do bezpłatnej konsultacji – porozmawiamy i sprawdzimy, czy możemy w tym pomóc.

Zapobieganie atakom SQL Injection

Powyższe przykłady to tylko niektóre z technik możliwych do wykorzystania w atakach typu SQL Injection. Pokazują jednak skalę zagrożenia oraz wskazują, jak można identyfikować omawiane luki bezpieczeństwa.

Dlatego też niezwykle istotne jest prawidłowe zabezpieczenie aplikacji przed omawianymi podatnościami. Kluczowa jest, przede wszystkim, sanityzacja danych wejściowych. Wszystkie informacje wprowadzane do programu powinny być traktowane jako potencjalne zagrożenie.

Należy wystrzegać konstruowania zapytań SQL poprzez łączenie stringów, do których wstawiane są dane przesłane przez użytkownika. Jest to najkrótsza droga do wprowadzenia luki umożliwiającej przeprowadzenie ataku typu SQL Injection.

Zamiast tego, generując dynamiczne zapytania do bazy, należy korzystać z parametryzowanych zapytań, gdzie zmienne przekazywane są jako parametry. Dzięki czemu spreparowane dane wejściowe nie są traktowane jako część zapytania, nawet jeśli zawierają pełnoprawny fragment SQL. Ponadto, można korzystać z procedur składowanych, co również zapobiega wstrzyknięciu złośliwego kodu SQL.

Konieczne jest także odpowiednie zabezpieczenie na poziomie bazy danych. Absolutnym minimum jest wdrożenie zasady najmniejszych uprawnień. W takim przypadku użytkownik bazodanowy, za pomocą którego łączy się aplikacja, powinien mieć nadane tylko te uprawnienia, które są niezbędne do prawidłowego działania aplikacji.

Należy również zadbać o to, żeby komunikaty błędów nie ujawniały szczegółów aplikacji i zapytania bazodanowego. Zamiast tego należy dać ogólny komunikat informujący o wystąpieniu błędu.

Warto pomyśleć o wykorzystaniu systemów typu WAF (Web Application Firewall), które pomagają odfiltrować zapytania URL zawierające potencjalnie niebezpieczne ciągi znaków.

Przykładowo Framework Laravel ma wbudowane mechanizmy zarówno do budowania zapytań (query builder), jak i bardzo wydajny ORM. Oba te mechanizmy bardzo skutecznie chronią przed wstrzyknięciem kodu SQL. Oczywiście, pod warunkiem ich prawidłowego wykorzystania. W Laravel również można wykonać czyste zapytanie SQL (raw query), które nie gwarantuje odporności na SQL Injection (przed czym ostrzega nawet oficjalna dokumentacja frameworka).

Wynika z tego, że samo zastosowanie bezpiecznych technologii jest niewystarczające, jeżeli nie idzie w parze z odpowiednimi standardami tworzenia kodu źródłowego i właściwym użyciem narzędzi oferowanych przez framework. Powinien być przyjęty jeden spójny sposób dostępu do danych dla projektu.

Podsumowując, ataki typu SQL Injection stanowią duże zagrożenie, jednak powszechnie znane są sposoby zabezpieczenia przed tymi zagrożeniami. Zapobieganie powstawaniu omawianych podatności jest stosunkowo proste w implementacji, dlatego tak ważna jest znajomość prawidłowego wdrożenia mechanizmów minimalizujących powstawanie tego typu luk w aplikacji.


Tworzysz aplikację webową i priorytetem jest dla Ciebie wysoka jakość kodu oraz bezpieczeństwo?

Umów się na bezpłatną konsultację. Sprawdźmy razem, jak możemy wesprzeć Twój projekt.

{Również może Ci się spodobać}