Przykład SQL Injection. Jak się zabezpieczyć przed SQL Injection?

3-mar-2012

Na atak SQL Injection narażone są programy, w których programista zdecydował się „sklejać” zapytania z fragmentów instrukcji SQL wpisanych przez programistę z fragmentami tekstu wpisywanymi przez użytkowników. Takie zapytanie, powstałe wskutek złączenia kodu programisty są następnie uruchamiane jako tzw. dynamiczny SQL. O ile w przypadku gdy użytkownik podaje „normalne” dane, zapytanie będzie działać zgodnie z założeniami, o tyle, gdy użytkownik odpowiednio spreparuje dane, może doprowadzić do uruchomienia własnych instrukcji. Zobaczmy to na przykładzie:

Najpierw załóżmy prostą tabelę:

USE tempdb
CREATE TABLE students
(Id INT IDENTITY,
Name NVARCHAR(50));

Do tej tabeli można wstawić rekord następującą instrukcją SQL:

INSERT INTO students VALUES('Robert')

Programista nie przewidujący ataku SQL Injection zbuduje swoją procedurę w oparciu o poniższą logikę:

DECLARE @s NVARCHAR(1000)
SET @s='Robert'
DECLARE @sql NVARCHAR(1000)='INSERT INTO students VALUES('''+@s+''')'
PRINT @sql
EXEC sp_executesql @statement=@sql

Przeanalizujmy to po kolei:

  • Zmienna @s odpowiada parametrowi przekazywanemu do procedury z zewnętrznej aplikacji (np ze strony internetowej. W tym przykładzie do zmiennej @s przypisujemy wartość wprowadzoną przez użytkownika.
  • Potem deklarujemy zmienną @sql. Ta zmienna zawiera w sobie instrukcję wstawiania rekordu (polecenie INSERT) jest jednak dynamicznie uzupełaniana o dane przesłane przez użytkownika.
  • Polecenie PRINT wyświetla informacyjnie polecenie zawarte w zmiennej @sql
  • Na koniec polecnie w zmiennej @sql jest uruchamiane, wykonasz to poleceniem sp_excutesql

Zobaczmy, jak można zmodyfikować zawartość danych przesyłanych przez użytkownika:

DECLARE @s NVARCHAR(1000)
SET @s='Robert''); DROP TABLE students;--'
DECLARE @sql NVARCHAR(1000)='INSERT INTO students VALUES('''+@s+''')'
PRINT @sql
EXEC sp_executesql @statement=@sql

Tym razem użytkownik wprowadził tekst: Robert”); DROP TABLE students;–

Przypomnijmy, że jeżeli w zmiennej tekstowej chcesz przesłać ’ (apostrof), który w SQL domyślnie oznacza początek i koniec tekstu, to należy go wpisać podwójnie: ”

Co więc stanie się teraz? Zapytanie, które ostatecznie jest uruchamiane wygląda następująco:

INSERT INTO students VALUES('Robert'); DROP TABLE students;--')

Oto co się stanie:

  • Do tabeli studenci zostanie wstawiony rekord z imieniem Robert. Średnik oznacza koniec instrukcji SQL.
  • Kolejna instrukcja to DROP TABLE students. To właśnie wstrzyknięty kod! Znak średnika kończy drugie polecenie SQL i przechodzimy do kolejnego.
  • Ostatnia instrukcja to komentarz, bo zaczyna się od — . Dzięki temu ciąg dalszy oryginalnej instrukcji SQL nie jest wykonywany, a całe zapytanie nie zgłasza błędu składni.

Jeżeli więc zaryzykowałeś i uruchomiłeś powyższy kod, to… nie masz już tabeli students!

Co zrobić aby zabezpieczyć się przed SQL Injection?

  • Nie stosować dynamicznego SQL, o ile można,
  • Badać przesyłane zmienne pod kątem obecności w nich znaku ; (koniec instrukcji SQL) — (komentarz) ’ (apostrof – cytowanie)
  • Nie wyświetlać zbyt szczegółowych komunikatów o błędzie. Potencjalny haker może wiele dowiedzieć się o strukturze twoich tabel na podstawie szczegółowego komunikatu o błędzie.
  • Używać parametrów. Parametry omówimy sobie niżej

Otóż, gdyby powyższy niebezpieczny fragment kodu przepisać następująco, zapytanie nie skończy się już aż tak źle:

DECLARE @s NVARCHAR(1000)
SET @s='Robert''); DROP TABLE students;--'
DECLARE @sql NVARCHAR(1000)='INSERT INTO students VALUES(@Name)'
DECLARE @ParmDefinition NVARCHAR(1000)= N'@Name NVARCHAR(100)';
PRINT @sql
EXEC sp_executesql @sql,@ParmDefinition,@Name=@s

Zapytanie wpisane początkowo w zmiennej @sql posługuje się parametrem @Name. Typ tego parametru został określony w zmiennej @ParamDefinition. Dzięki zmiennej i definicji typu tej zmiennej polecenie sp_executesql „wie”, że powinno otrzymać w parametrze @Name wartość tekstową. Tym razem wywołując polecenie sp_executesql nie utracisz tabeli students. Do tabeli zostanie jednak wstawiony student o dziwnym imieniu:

Komentarze są wyłączone

Autor: Rafał Kraik