Zastrzyk prosto w serce

Przykład 3

Unikanie uwierzytelnienia

Powyższy fragment kodu może również posłużyć do wyjaśnienia, w jaki sposób, umiejętnie manipulując wprowadzanymi danymi, można ominąć zaprojektowany mechanizm uwierzytelniający. Funkcja uwierzytelniająca przedstawiona w listingu 2 wykonuje zapytanie SQL i sprawdza liczbę zwróconych rekordów. Jeżeli zapytanie zwróciło dokładnie jeden rekord, oznacza to, że użytkownik wpisał poprawny login oraz hasło i funkcja MyAuth zwróci identyfikator użytkownika. Jeżeli jednak użytkownik wprowadzi do formularza poniższy ciąg znaków:

Username: ' or 1 = 1--

skrypt wykona następujące zapytanie SQL:

SELECT id FROM users WHERE username = '' OR 1 = 1

W rezultacie intruz będzie mógł zalogować się z prawami pierwszego użytkownika w bazie. W wypadku tego skryptu można jednak pójść dalej i spróbować zalogować się jako konkretny użytkownik. Wystarczy w pole username wpisać:

Username: administrator'--

a wykona się zapytanie:

SELECT id FROM users WHERE username = 'administrator'

Struktura danych na celowniku

Prawdopodobieństwo skuteczności ataku jest tym większe, im bardziej szczegółowa jest wiedza intruza na temat struktury bazy danych, a więc nazw tabel i kolumn oraz kształtu relacji między tabelami. Informacje o strukturze bazy można nierzadko pozyskać, konstruując błędne polecenia SQL. Serwer zwraca często komunikat o błędzie, w którym można znaleźć informacje wskazujące na strukturę bazy. Jeżeli w powyższym przykładzie w polu username zostanie wpisany ciąg znaków:

Username: ' HAVING 1 = 1--

do bazy zostanie wysłane takie zapytanie:

SELECT id FROM users WHERE username = '' HAVING 1 = 1

Wyrażenie to jest poprawne składniowo, jest jednak niepoprawne ze względu na strukturę danych. W rezultacie baza zwróci następujący komunikat:

Attribute users.id must be GROUPed or used in an aggregate function.

W ten sposób intruz uzyskał informacje o nazwie tablicy oraz o nazwie pierwszej kolumny. Nazwy kolejnych kolumn można uzyskać np. przez odpowiednie doklejanie klauzuli GROUP BY.

Jak się bronić?

Jak bronić się przed atakami typu SQL injection? Trzeba podkreślić, że gros odpowiedzialności ciąży na projektantach i programistach interfejsów dostępu do danych. Ogólne wskazówki, których zastosowanie zdecydowanie zmniejsza ryzyko ataku, są następujące:

- Wszystkie dane pochodzące z zewnątrz aplikacji powinny być filtrowane. Procedury powinny przepuszczać tylko te znaki/ciągi, które są dopuszczalne w danym kontekście. Szczególnie ważne jest wyszukiwanie słów kluczowych, takich jak SELECT. W powyższych przykładach uniemożliwiłoby to umieszczenie w ciągu znaków znaków specjalnych takich jak cudzysłów, apostrof czy podwójny myślnik, a więc zapobiegłoby atakowi.

- Przy nadawaniu uprawnień należy stosować zasadę najmniejszych przywilejów. W fazie projektowania należy zdefiniować najmniejszy zestaw informacji niezbędny do wykonania danego zadania. Szczególną uwagę należy zwrócić na prawa dostępu do wewnętrznych struktur bazy danych. W przykładzie 1 można było np. odczytać zawartość widoku all_users, chociaż przywileje te były zbędne do prawidłowego działania programu.

- Precyzyjne określenie funkcji dostępnych użytkownikowi za pośrednictwem interfejsu. Operacje te należy precyzyjnie udokumentować. W przypadku operacji modyfikacji lub dodawania rekordów w bazie danych należy zamknąć ich działanie w osobnych funkcjach, separując operacje dostępu do bazy danych od warstwy prezentacji. Zgodnie z zasadą pięrwszą, każda taka funkcja powinna mieć ściśle zdefiniowane parametry wejściowe.

- W środowisku aplikacji nie powinno być żadnych zbędnych do jej działania plików. Bardzo często zdarza się, że programiści, edytując dla przykładu plik adduser.php, zapominają, iż w trakcie pracy zachowali jego wcześniejszą wersję pod nazwą adduser.php.bak lub adduser.bak. W takim przypadku potencjalny intruz może bardzo łatwo odszukaś taki plik i uzyskać z niego szczegółowe informacje na temat struktury i procedur dostępu do bazy danych.

Uszczelnianie aplikacji

Aby zmniejszyć ryzyko ataku typu SQL injection, warto przestrzegać kilku zasd:

  • Dane pochodzące z zewnątrz aplikacji powinny być filtrowane

  • Przy nadawaniu uprawnień należy stosować zasadę najmniejszych przywilejów

  • Precyzyjne określenie funkcji dostępnych użytkownikowi za pośrednictwem interfejsu

  • W środowisku aplikacji nie powinno być żadnych zbędnych do jej działania plików

TOP 200