Obrona przed atakami SQL-Injection z punktu widzenia administratora

Wojciech Dworakowski
wojtekd@securing.pl

W poprzednim numerze PLOUG’tek opisywałem technikę
atakowania serwerów WWW sprzężonych z bazami danych zwaną SQL-injection. Dla
przypomnienia – technika ta polega na takiej manipulacji parametrami
zapytania SQL pobieranymi z zewnątrz, że do zapytania oryginalnego jest
„doklejana” dodatkowa komenda SQL intruza. W zależności od
stosowanej jako „back-end” bazy danych i sposobu integracji z
serwerem www, mogła to być zupełnie niezależna komenda SQL czy DML/DDL lub
zapytanie SQL doklejone do oryginalnego za pomocą składni UNION SELECT.
Ponadto, intruz przy pomocy tej techniki może zmieniać logikę działania
aplikacji. Typowym przykładem jest doklejenie zawsze prawdziwego warunku np.
„OR 1=1” na końcu składni WHERE.

Możliwość wykorzystania tej metody oraz stopień zagrożenia
wiąże się ściśle z logiką działania aplikacji WWW. Zwykle zagrożenie to
jest bardzo duże – tym bardziej, że nie są to aplikacje standardowe,
lecz z reguły tworzone na potrzeby konkretnego projektu.

Jedynym w 100% skutecznym sposobem ochrony jest prewencja
– czyli pisanie bezpiecznych skryptów i aplikacji działających na
serwerze www. Zestaw podstawowych zasad bezpieczeństwa przy projektowaniu metod
server-side – przedstawiłem w poprzednim artykule.

Co jednak może zrobić administrator bazy danych lub sieci?
Z reguły ma on ograniczony wpływ na kod który jest publikowany na jego
serwerze. Kod tworzą deweloperzy, a administrator ma zapewnić, że będzie on
działał na serwerach. Im większa firma, tym bardziej te dwie funkcje są od
siebie oddalone i tym mniejszy jest wpływ administratora na bezpieczeństwo
samego kodu umieszczonego na serwerze aplikacji.

Częstokroć kod ten pochodzi ze źródeł zewnętrznych.
Jest tworzony na zlecenie lub jest to po prostu fragment jakiegoś produktu
integrującego serwer WWW i bazę danych. W takim wypadku wpływ administratora
na jakość i bezpieczeństwo kodu udostępnianego na serwerze WWW jest jeszcze
mniejsza.

Spróbuję podać kilka metod technicznych, które mogą
podnieść bezpieczeństwo serwera aplikacyjnego, niezależnie od udostępnianego
na nim kodu i rodzaju zastosowanej metody server-side (mod_plsql, JSP,
ASP, PHP, itd.). Z góry zaznaczam, że nie są to sposoby skuteczne w 100%, każdy
z nich posiada swoje ograniczenia. Jednak stosowanie tych dodatkowych metod może
znacznie podnieść poprzeczkę, którą musi pokonać intruz aby wykorzystać
metodę SQL-injection.

Podam m.in. sposoby wykorzystujące:

  • Zaawansowane produkty firewall (na przykładzie
    Checkpoint Firewall-1)
  • Software uzupełniający – tzw. application
    firewall (na przykładzie NGSecureWeb)

Schemat przetwarzania zapytań do serwera aplikacyjnego

Na początek trochę teorii, która pozwoli lepiej zrozumieć
działanie i potencjalne umiejscowienie mechanizmów zabezpieczających. Prześledźmy,
w jaki sposób przekazywane jest typowe wykonanie zapytania do bazy za pośrednictwem
strony www.

  1. Strona WWW wyświetlona w przeglądarce pobiera od użytkownika
    dane. Zwykle jest to realizowane przez wypełnienie formularza na stronie,
    ale równie dobrze może to być kliknięcie określonej części strony
    – wszystko zależy od tego, w jaki sposób autor strony zorganizował
    pobieranie danych.
  2. Po zatwierdzeniu wprowadzonych danych przez użytkownika
    (np. przez naciśnięcie klawisza na formularzu), dane są przekazywane do
    serwera. Zawsze odbywa się to przez wywołanie jakiegoś skryptu lub
    procedury po stronie serwera i przekazanie do niej wprowadzonych przez użytkownika
    danych. W przypadku Oracle, może to być np. procedura PL/SQL udostępniona
    przez mod_plsql, skrypt JSP, PHP, ASP i wiele innych.
    Protokół HTTP umożliwia dwie podstawowe metody odwoływania się do
    serwera HTTP:

    • GET – główna metoda komunikacji
      przeglądarki z serwerem.
      Składnia:
      GET /sciezka/plik?parametr1=wartosc1&parametr2=wartosc2
      W tym wypadku wywoływanym plikiem jest skrypt
      przetwarzający wprowadzone w przeglądarce dane. Dane wprowadzone w
      formularzu (lub w inny sposób), są przekazywane w parametrach.
      Np:
      GET /search/search_form1.jsp?product=komputer&lang=pl
    • POST – metoda wykorzystywana, gdy
      zachodzi konieczność przesłania większej ilości danych. Składnia jest
      identyczna jak przy metodzie GET, jednak po wywołaniu, skrypt po stronie
      serwera przyjmuje parametry również na standardowe wejście.
      Np:
      POST /search/search_form2.jsp
      product=komputer&lang=pl
      Metoda ta najczęściej jest wykorzystywana przy wysyłaniu
      danych z formularza.
      Uwaga: W metodzie POST dopuszczalne jest też przekazanie
      parametrów w linii wywołania po znaku „?” (tak jak GET).

    O wyborze metody decyduje programista kodujący strony WWW i
    skrypty oraz procedury działające po stronie serwera.
    Całość wywołania: METODA /sciezka/plik?parametry nosi
    nazwę URI (Universal Resource Identifier).

  3. Wywołany skrypt lub procedura przetwarza parametry
    otrzymane od przeglądarki i konstruuje z nich zapytanie do bazy danych.
  4. Zapytanie to jest wykonywane przez bazę z uprawnieniami
    jakie narzucił programista.
  5. Jego rezultat jest przetwarzany przez skrypt wywołujący
    – w rezultacie powstaje kod HTML, który jest zwracany do przeglądarki.

Jak widać, niewiele tu może zależeć od administratora
bazy, serwera WWW czy sieci.

Obrona na poziomie bazy danych

Zauważmy, że z punktu widzenia bazy danych, zapytanie jest
wykonywane przez zwykłego użytkownika (zdefiniowanego w skrypcie wykonującym
połączenie do bazy). Jedyną formą obrony są więc uprawnienia, jakie ma ten
użytkownik. Należy tu zastosować zasadę najmniejszych przywilejów. Użytkownik
związany z aplikacją WWW powinien mieć najmniejszy możliwy zestaw przywilejów,
niezbędny do wykonania działań na bazie przewidzianych przez projektanta
aplikacji. W szczególności należy rozważyć uprawnienia do wykonywania
procedur w bazie oraz uprawnienia do modyfikowania danych. Warto też sprawdzić,
czy użytkownik jest członkiem grupy PUBLIC i jakie przywileje się z tym wiążą.

Ingerencja w poziom uprawnień użytkownika, związanego z
aplikacją WWW w bazie danych, nie zawsze jest możliwa. Poza tym, nie
zabezpiecza to przed samym atakiem SQL-injection, lecz jedynie ogranicza jego
skutki.

Znacznie lepszym sposobem jest filtrowanie zapytań płynących
do serwera WWW.

Filtrowanie zapytań do serwera

Zapytania do serwera WWW, zintegrowanego z bazą danych, jest
przekazywane za pośrednictwem metody HTTP GET lub POST. Atak SQL-injection jest
wykonywany przez doklejenie swojego zapytania do jednego bądź wielu parametrów
przekazywanych w metodzie GET lub POST. Z punktu widzenia protokołu HTTP, atak
SQL-injection nie różni się niczym od standardowego odwołania do serwera
HTTP. Np:

http://serwer_oracle/demo/sql/tag/sample2.jsp?cond=sal%3D800+union+select+username%2C+user_id+from+all_users

Zaznaczony fragment odwołania HTTP, to atak SQL-injection.
Dla tradycyjnych firewalli i sytemów IDS jest to prawidłowe wywołanie HTTP.
Podobnie jest z metodą POST.

Jedyną logiczną metodą wykrywania tego typu ataków wydaje
się być wyszukiwanie pewnych słów kluczowych w wywołaniu HTTP. Typowe słowa
kluczowe które mogą oznaczać próbę ataku:

SELECT, DELETE, INSERT, UPDATE
UNION SELECT
OR 1=1
OR A=A
— (znak komentarza)
‚ (pojedynczy cudzysłów)

Warto zauważyć, że słowa te mogą również oznaczać
normalną aktywność użytkownika. Np. w formularzu do wyszukiwania produktów,
użytkownik może poszukiwać produktu o nazwie „Update Magic” lub
„Selector”. Stosowanie metod detekcji opartych na słowach
kluczowych wymaga bardzo szczegółowego doboru zabronionych fraz i może
powodować fałszywe alarmy oraz blokowanie prawidłowego ruchu.

Jeśli jest to możliwe, należy używać w miejsce
pojedynczych słów kluczowych, całych wyrażeń zastępując ciągi znaków
odpowiednim znacznikiem, np:

zamiast SELECT użyć SELECT*FROM*

Oczywiście, sposób kodowania wyrażeń zależy od
zastosowanej implementacji filtrowania.

Filtrowanie można stosować w różnych miejscach, przez które
przechodzi zapytanie HTTP. Poniżej przedstawię możliwości detekcji i
blokowania ataków SQL-injection na zaawansowanym firewallu oraz na samym
serwerze WWW.

Filtrowanie na firewallu (Firewall-1)

Filtrowanie zapytań HTTP za pomocą słów (lub wyrażeń)
kluczowych, można zaimplementować na firewallu. Jednak musi to być firewall z
możliwością analizy protokołu HTTP. Zwykły firewall ma dostęp jedynie do
czwartej warstwy modelu OSI, a więc nie ma możliwości dekodowania i analizy
protokołu HTTP. Bardziej zaawansowane firewalle potrafią częściowo analizować
ruch HTTP i czasami umieją blokować ruch na podstawie słów kluczowych.

Przykładem takiego rozwiązania jest Checkpoint Firewall-1.
Jedną z jego opcji jest możliwość prostej analizy ruchu HTTP pod względem
zawartości URI.

Żeby dodać regułę blokującą ruch w zależności od
zawartości URI, należy najpierw zdefiniować zasób (w tym wypadku zasobem
jest opis ataku). Z poziomu Checkpoint Policy Editor wykonać należy:

Manage -> Resources -> New -> URI

W pole „Name” należy wpisać nazwę
definiowanego zasobu – np. „SQL-injection”, zaś w polu
„URI Match Specification Type” zaznaczyć „Wild Cards”.

Na zakładce „Match” mamy możliwość
zdefiniowania szczegółów tworzonego zasobu. Tu należy jak najdokładniej
opisać atak SQL-injection który chcemy blokować:

Schemes: http

Methods: GET, POST

Query: *SELECT*FROM*

Dodatkowo – na zakładce „Action” w polu
„Replacement Uri” można zdefiniować stronę na którą będzie
przekierowany intruz. Istnieje również możliwość importowania wyrażeń z
pliku.

Regułę blokującą zdefiniowany przed chwilą zasób
„SQL-injection” dodajemy tak jak każdą inną regułę filtrowania,
z tym że w polu „Service”, po kliknięciu prawym klawiszem myszy
wybieramy „Add with resource”. Następnie wybieramy usługę
„http” a w polu „Resource” zdefiniowany przez nas zasób
„SQL-injection”.

Poniższy rysunek przedstawia gotową przykładową regułkę
blokującą niektóre ataki SQL-injection:

Podstawową wadą Firewall-1 w tym zakresie jest możliwość
filtrowania jedynie po zawartości URI. Uniemożliwia to ochronę przed atakami
SQL-injection tych aplikacji, które przesyłają dane pobrane od przeglądarki
za pomocą metody POST, ponieważ w tym wypadku, dane w których może być
zawarty atak SQL-injection, są przekazywane poza URI. Natomiast zabezpieczy to
nas przed atakami na strony które przekazują dane w parametrach URI, po znaku
„?”.

Niewątpliwą zaletą blokowania ataków SQL-injection na
firewallu jest możliwość ochronienia wielu serwerów WWW i aplikacji, za
pomocą jednego urządzenia i jednego zestawu reguł. Znacznie upraszcza to wdrożenie
i zarządzanie przy rozbudowanych infrastrukturach, gdzie musimy chronić wiele
serwerów WWW korzystających z baz danych.

Natomiast ogromną wadą takiego rozwiązania jest niemożność
analizowania ruchu HTTPS (SSL). Ruch ten jest zaszyfrowany, a co za tym idzie
– niemożliwy do przeanalizowania przez firewall. Warto zauważyć że
fragmenty aplikacji WWW chronione protokołem SSL, z reguły są połączone z
bardzo istotnymi informacjami w bazie danych, tak więc tym bardziej należałoby
je chronić.

Obrona na poziomie serwera WWW

Lepszym rozwiązaniem wydaje się być blokowanie ataków na
samym serwerze WWW. Oracle HTTP Listener, to standardowy serwer WWW – Apache z
dodatkowymi modułami integrującymi go z Oracle. Apache umożliwia rozszerzanie
funkcjonalności serwera przez doładowywanie modułów dynamicznych DSO, bez
konieczności rekompilacji Apache. Daje to możliwość zaprojektowania rozwiązania
filtrującego w postaci modułu Apache. Takie rozwiązanie daje najlepszą
integrację z serwerem WWW. Na tego typu pomyśle bazuje m.in. oprogramowanie
NGSecureWeb.

Moduł serwera WWW (NGSecureWeb)

NGSecureWeb to przykład oprogramowania typu application
firewall
. Oprogramowanie takie działa podobnie do firewalla (filtruje
ruch), lecz jest przystosowane tylko do specyfiki konkretnego protokołu
sieciowego i konkretnej aplikacji. W tym wypadku – NGSecureWeb jest
przeznaczony do współpracy z serwerem WWW. Potrafi integrować się z Apache
1.3, Microsoft IIS oraz serwerami iPlanet (Sun One).

Do instalacji jest niezbędny program axps, który umieszcza
w pliku konfiguracyjnym Apache (httpd.conf) odwołanie do modułu filtrującego
– mod_ngswa. Do oprogramowania dołączony jest graficzny konfigurator. Można
też administrować nim przez edycję plików konfiguracyjnych.

Działanie modułu jest bardzo proste. Moduł przechwytuje
zlecenia płynące do serwera WWW w ostatniej fazie przetwarzania przez Apache.
Dzięki temu może analizować i blokować dane, które faktycznie zostaną
przekazane do aplikacji, po „odarciu” ze wszystkich zewnętrznych
warstw. Dzięki temu można filtrować zlecenia niezależnie od tego, czy są
one przekazywane przez połączenia zwykłe, szyfrowane SSL, czy też zakodowane
w każdy inny sposób. Zlecenie jest analizowane po dokonaniu wszelkich
koniecznych przekształceń przez serwer WWW. Dzięki temu filtr jest np.
odporny na techniki oszukiwania systemów zabezpieczających, polegające na
zakodowaniu części URI hexadecymalnie.

NGSecureWeb potrafi wykrywać i blokować kilka typów ataków
na serwery aplikacyjne. Do obrony przed atakami SQL-injection możemy wykorzystać
filtr „Forbidden Words Protection”. Wykrywa on w zleceniu HTTP słowa
kluczowe. Poniższy rysunek przedstawia przykładową konfigurację odrzucającą
wszystkie zlecenia zawierające w sobie słowo SELECT.

W odróżnieniu od przykładu z Firewall-1, oprogramowanie
NGSecureWeb potrafi analizować również argumenty przekazywane w metodzie
POST. Dzięki temu można filtrować każdy sposób komunikacji między przeglądarką
a serwerem.

Po skonfigurowaniu słowa kluczowego SELECT, każda próba użycia
go w dowolnej części zlecenia HTTP spowoduje zwrócenie przez serwer strony
informującej o zablokowaniu ataku.

Rozwiązanie to nie jest jednak wolne od wad. Za największą
uważam to, że do opisania ataku da się używać tylko i wyłącznie
pojedynczych słów, a nie np. wyrażeń regularnych. Ponadto intruz zawsze jest
informowany o tym, że atak został zablokowany przez NGSecureWeb.

Warto jednak zauważyć, że jest to oprogramowanie
przeznaczone do blokowania różnego typu klas ataków na serwery aplikacyjne,
nie tylko ataków SQL-injection (np. wywoływanie zdalnych komend, buffer
overflow
, manipulacje nagłówkami HTTP, directory traversal).

Podsumowanie

Ataki SQL-injection są dość ciężkie do wykrycia i
zablokowania przez to, że są one przenoszone przez zwykłe wywołania protokołu
HTTP. Jedynym sposobem wykrywania i blokowania ich, jest filtrowanie ruchu HTTP
po słowach kluczowych. Wdrożenie tej metody wymaga jednak szczegółowego
ustalenia zestawu wykrywanych znaków (np. wpisanie w formularzu WWW słowa
„select” nie zawsze oznacza atak). W ustaleniu szczegółowych reguł,
znacznie pomaga zastosowanie wyrażeń a nie pojedynczych słów.

Filtrowanie ruchu na firewallu wyposażonym w możliwość
analizy protokołu HTTP wyklucza możliwość analizy ruchu zaszyfrowanego SSL,
bardzo często wykorzystywanego w kluczowych częściach aplikacji. Znacznie
lepszym rozwiązaniem jest filtrowanie ruchu wewnątrz serwera WWW, po dokonaniu
przez niego wszelkich interpretacji.

Pamiętajmy jednak, że opisywane tutaj metody nie dają pełnego
zabezpieczenia. Typ możliwych do zastosowania ataków SQL-injection jest ściśle
zależny od logiki działania aplikacji internetowej oraz sposobu integracji
serwera WWW z bazą danych. Znacznie większy poziom bezpieczeństwa możemy osiągnąć
stosując zasady bezpiecznego projektowania i programowania aplikacji
internetowych, oraz audytując ich kod pod względem bezpieczeństwa.

Artykuł powstał podczas prac projektowych nad
oprogramowaniem służącym do detekcji i blokowania ataków SQL-injection, które
powstaje w naszej firmie. Filtr będzie działać na poziomie serwera WWW i będzie
przystosowany do pracy z Oracle HTTP Listener.

W Internecie:

http://ngsec.com/ngproducts/ngsw/
http://www.sqlsecurity.com/DesktopDefault.aspx?tabindex=2&tabid=3
http://online.securityfocus.com/infocus/1646