Co to jest SQL Injection?
Obiło Ci się o uszy?
SQL Injection to jeden z typów ataków na aplikacje internetowe. Skierowany jest głównie na wykradnięcie lub zniszczenie danych z bazy danych.
W większości, jego celem padają firmy, organizacje i instytucje przechowujące wrażliwe dane osób powiązanych. W szczególności hasła, numery kart kredytowych, dane teleadresowe itp.
Jednak nikt nie jest bezpieczny…
Bez wątpienia jest to jeden z najbardziej popularnych ataków w dzisiejszych czasach.
Nic dziwnego. W końcu umożliwia uzyskanie największych korzyści dla atakującego.
Injection z angielskiego to 'wstrzykiwanie’. Atak polega na wstrzyknięciu w aplikację komendy SQL, która wykona się obok normalnych komend SQLowych, bez wiedzy webmastera.
W jaki sposób?
Zobacz.
Na stronie umożliwiasz wpisywanie danych swoim użytkownikom poprzez inputy (tekstowe, comboboxy, buttony itp.). Następnie, formularz HTML wypełniony treścią tych inputów jest przekazywany do skryptu po stronie serwera. W zależności od potrzeb, metodą POST lub GET.
Docelowo, chcesz uzyskać od odwiedzającego jego login, imię lub jakiekolwiek inne dane. Zakładasz, że w polu 'Imię’ otrzymasz coś w rodzaju 'Janek’ lub 'Stasia’.
Wtedy w swoim skrypcie dodającym użytkownika do bazy wstawiasz w kolumnę 'FirstName’ wartość z inputu 'Imię’.
Co jednak stanie się, jeśli użytkownik okaże się być sprytnym hackerem i wpisze potencjalnie niebezpieczne uzupełnienie komendy SQL?
Np.:
„Ronaldo’); Drop Table users;”
Wtedy usunie nam całą tabelę users. Doszczętnie.
Ten fragment kodu zakłada, że tabelę z użytkownikami nazwaliśmy users. Często nazywa się inaczej i atak okaże się nieskuteczny. Jest to jednak prosty przykład, jak działa SQL Injection.
Jak to dokładnie działa?
Input na stronie traktowany jest zazwyczaj 1:1 z wartością kolumny z bazy danych. Wstawiasz wartość z inputu jako wartość dla poleceń SQL.
Hacker, odpowiednio preparując wartość podawaną w inpucie, stara się wykonać dodatkową instrukcję lub dodać warunek do predefiniowanej kwerendy.
Często w aplikacjach stosowane jest zapytanie 'Zwróć mi usera, którego login to XXX i hasło to YYYPass’. Na podstawie jego wyniku serwer stwierdza, czy podane dane logowania są poprawne i czy ma przepuścić użytkownika do części chronionej.
Po ataku SQL Injection może się okazać, że zapytanie przybrało formę ’Zwróć mi usera, którego login to XXX i hasło to YYYPass lub 1=1′.
Wstrzyknięty dodatkowy warunek 'lub 1=1′ powoduje, że zapytanie zawsze zwróci TRUE. Skoro tak, serwer zawsze zaloguje atakującego i przepuści go do części przeznaczonej tylko dla uwierzytelnionych użytkowników.
Kiedy to się zaczęło?
Praktycznie odkąd powstały pierwsze aplikacje webowe. Gdy tylko strony zaczęły robić nieco więcej niż tylko wyświetlać statyczne informacje, zaczęły się ataki.
Kilkanaście lat temu webmasterzy nie musieli się martwić tego typu rzeczami. Praktycznie każda strona była oparta na statycznym HTML.
Dzisiaj to praktycznie standard. Spamboty krążą po całym internecie, wyłuskując dane logowania oraz wrzucając treści przepełnione linkami. Obrona przed nimi to podstawa każdego projektu internetowego. Ze słabymi zabezpieczeniami niemal w momencie Twoja strona stanie się siedliskiem tysięcy linków do stron przepełnionych hazardem i viagrą.
Najważniejsze pytanie – jak się przed tym bronić?
Ten poradnik pomoże Ci zabezpieczyć swoją stronę przed SQL Injection.
Kwestia nr 1. Traktuj każdy input jako potencjalną furtkę dla atakującego!
Nawet jeśli jest to checkbox czy radio button. Telegram HTTP zawsze można spreparować. Nigdy nie możesz być pewien, że wartości przyjdą zgodne z umieszczonymi do wyboru w formularzu HTML.
Zawsze filtruj każdą wartość wprowadzaną przez użytkownika.
Możesz użyć wbudowanych funkcji językowych w zależności, z jakiej technologii korzystasz.
W PHP możesz np. użyć mysqli::escape_string() jeśli korzystasz z obiektu MySQLi do łączenia się bazą MySQL.
Dodatkowo, za jednym zamachem warto zabezpieczyć się przed XSS (Cross-Site Scripting). Służą do tego funkcje htmlspecialchars lub strip_tags. Poczytaj więcej o obronie przed XSS tutaj: http://4programmers.net/PHP/Ochrona_przed_XSS_-_podstawy
Prepared Queries jako sposób na walkę z SQL Injection.
Możesz również zastosować prepared queries w celu zaaplikowania jedynie poprawnych parametrów i wycięcia niebezpieczeństw. Podobne konstrukcje występują zarówno dla MySQLi jak i obiektów PDO.
Przykład MySQLi – http://php.net/manual/pl/mysqli.prepare.php
Przykład PDO – http://php.net/manual/pl/pdo.prepared-statements.php
Dodatkowym trikiem, który często stosuję, a o którym nie wspomina się często w sieci, jest rzutowanie zmiennej na oczekiwany typ. Programiści, którzy swój warsztat budowali wyłacznie na PHP i JavaScript często zapominają, czym są typy zmiennych. Że w ogóle istnieją.
A prawdą jest, że istnieją i warto z nich korzystać.
Jak wykorzystać rzutowanie do obrony przed SQL Injection?
W momencie przetwarzania wartości w inputach, rzutuję je na oczekiwany typ zmiennej. W przypadku wieku lub roku urodzenia, działa to niezawodnie.
Rzutowanie polega na jawnym określeniu typu zmiennej, w jaki sposób interpreter PHP ma ją dalej przetwarzać. Tak np. mając wartość w inpucie „21′ Or 1=1;” po rzutowaniu na Inta otrzymamy 21. I z tą wartością będziemy mieć do czynienia w dalszej części skryptu.
Rzutowanie działa na wszystkie pola oprócz stringów. Każda zmienna domyślnie przychodzi w postaci ciągu znaków (stringa). Więc rzutowanie stringa na stringa nic nam nie da.
Jednak daty, wartości liczbowe, zmiennoprzecinkowe i logiczne można łatwo zabezpieczyć właśnie rzutując je na odpowiedni typ.
Prawa użytkownika bazy danych.
Dodatkowym zabezpieczeniem przed atakiem jest przydzielenie odpowiednich praw dla użytkownika wykonującego skrypty SQL w programie.
Chodzi o login i hasło, które podajesz przy tworzeniu połączenia z bazą SQL w aplikacji.
Istotną sprawą jest, aby taki użytkownik miał jak najmniejsze możliwe prawa. Jeśli korzystasz głównie z wyświetlania i wyszukiwania treści, często wystarczy sam SELECT.
Wtedy, nawet przebijając się przez Twoją warstwę obronną, hacker nie będzie mógł nic zmienić na bazie. Nie
zmienia to faktu, że wciąż może wyciągnąć dane zawarte w bazie. Natomiast potencjalne zagrożenie wydaje się dużo mniejsze.
Jeśli dodajesz nowe treści do bazy, konieczny może okazać się insert i/lub update. Jednak w żadnym razie nie dawaj mu pełnych praw.
Delete również wydaje się ryzykowny z punktu widzenia bezpieczeństwa.
Najlepiej byłoby, gdybyś przyjął politykę nieusuwania niczego z bazy.
Dobrą praktyką jest dodanie kolumny w stylu 'isDeleted’ lub 'isArchived’. Wtedy, chcąc usunąć rekord, updatujesz jej wartość na 1. Wszystkie selecty muszą mieć dodatkowy warunek, że isDeleted musi być 0 lub Null.
Parę słów na koniec, żeby nic nie uciekło.
SQL Injection to jeden z najbardziej niebezpiecznych ataków hackerskich.
Umożliwia wykradanie wrażliwych, tajnych danych z aplikacji. Do tego potrafi spustoszyć działającą bazę danych, dla której jedynym ratunkiem jest restore z utworzonego wcześniej backupu.
Mimo, iż brzmi to groźnie, można się przed nim zabezpieczyć. Poznałeś tu kilka zasad i tricków, które pomagają znacznie zmniejszyć ryzyko udanego ataku.
Ograniczenie zaufania do użytkowników to podstawa. Każda wartość wprowadzana przez gościa na stronie może zostać spreparowana przez hackera i użyta do wstrzyknięcia skryptu SQL.
Minimalizuj skutki potencjalnego ataku poprzez ograniczenie praw użytkownika bazy danych. Używaj wyłącznie wymaganego minimum do poprawnego działania aplikacji.
To byłoby na tyle. Jeśli chcesz uchronić swoje strony przed masowym spamem i nałożeniem filtra przez Google, koniecznie zabezpiecz swoje inputy.
Fajny artykuł. Dodałbym jednak informacje na temat ślepych ataków (blind sql injection).