Iniekcji SQL

Iniekcji SQL jest atak, w której złośliwy kod jest wstawiany do ciągów, które później są przekazywane do wystąpienie SQL Server do analizowania i wykonanie.Postępowanie konstrukcje instrukcji SQL należy poddać przeglądowi dla iniekcją, ponieważ SQL Server spowoduje wykonać wszystkich odbieranych zapytań syntaktycznie prawidłowa.Nawet sparametryzowana danych można manipulować przez wykwalifikowanych i oznaczany osoba atakująca.

Formularz podstawowy iniekcji SQL składa się z bezpośredniego wstawiania kodu do zmiennych danych wejściowych użytkownika, które są tak łączone z poleceń SQL i wykonywane.Mniej bezpośredni atak injects złośliwego kodu do ciągów, które są przeznaczone do przechowywania w tabela lub w postaci metadane.Gdy później sklejeniu ciągów przechowywane do dynamicznego polecenia SQL złośliwy kod jest wykonywany.

Proces iniekcji działa przedwczesne zakończenie ciąg tekstowego i dołączenie nowego polecenia.Ponieważ wstawionego polecenia mogą mieć dodatkowe ciągi dołączany przed jego wykonaniem, malefactor kończy wtryskiwanego ciąg znacznik komentarza "--".Następny tekst jest ignorowany w wykonanie czas.

Poniższy skrypt zawiera proste iniekcji SQL.Skrypt buduje kwerendę SQL poprzez konkatenację kodowana ciągi wraz z ciąg wprowadzonego przez użytkownika:

var Shipcity;
ShipCity = Request.form ("ShipCity");
var sql = "select * from OrdersTable where ShipCity = '" + ShipCity + "'";

Użytkownik jest monitowany o wprowadzenie nazwy miasta.Jeśli użytkownik wprowadzi Redmond, kwerendy zmontowane przez skrypt wygląda podobnie do następującego:

SELECT * FROM OrdersTable WHERE ShipCity = 'Redmond'

Jednak przyjmijmy, że użytkownik wprowadzi następujące:

Redmond'; drop table OrdersTable--

W takim przypadek następującej kwerendy jest montowany przez skrypt:

SELECT * FROM OrdersTable WHERE ShipCity = 'Redmond';drop table OrdersTable--'

Średnik (;) oznacza koniec jednej kwerendy i rozpoczęcia drugiego.Podwójne łącznik (-) wskazuje, że pozostałe bieżącego wiersza jest komentarz i powinno być zignorowane.Jeżeli zmodyfikowany kod jest poprawne syntaktycznie, będą wykonywane przez serwer.Gdy SQL Server przetwarza tej instrukcja SQL Server najpierw wybierz opcję wszystkie rekordy OrdersTable gdzie ShipCity jest Redmond.Następnie SQL Server będzie porzucać OrdersTable.

Jak długo wtryskiwanego kod SQL jest poprawne syntaktycznie, manipulowanie nie można wykryć programowo.Dlatego należy sprawdzić poprawność wszystkich danych wejściowych użytkownika i dokładnie przejrzyj kod, który wykonuje konstruowanej polecenia SQL na serwerze, którego używasz.Kodowania najważniejsze są opisane w następnych sekcjach w tym temacie.

Sprawdź poprawność wszystkich danych wejściowych

Sprawdzanie poprawności danych wejściowych użytkownika przez badania typu, długość, formatu i zakres.Wprowadzając środki ostrożności przeciwko złośliwych danych, należy rozważyć scenariuszy architektury i wdrażania aplikacji.Należy pamiętać, że bezpieczne środowisko jest kopiowany programów przeznaczonych do uruchamiania w bezpiecznym środowisku.Następujące sugestie należy uznać za najważniejsze wskazówki:

  • Wprowadzać żadnych założeń rozmiar, typ lub zawartości dane odebrane przez aplikację.Na przykład należy ustawić następujące oceny:

    • Jak aplikacja będzie działać, jeśli wadliwe lub złośliwy użytkownik wprowadzi pliku MPEG 10 megabajtów, gdy aplikacja oczekuje kodu pocztowego?

    • Jak aplikacja będzie działać, jeśli instrukcja DROP TABLE jest osadzony pole tekstowym?

  • Przetestuj rozmiar i typ danych wejściowych danych i wymuszenia właściwych limitów.Może to zapobiec przekroczenia buforu zamierzonego.

  • Testowanie zawartości zmiennych typu ciąg i akceptuje tylko wartości oczekiwane.Odrzucić wpisy zawierające dane binarne, sekwencje escape i znaki komentarza.To może zapobiec uruchomienie skryptu, a także ochrony przeciwko nadużyciom niektóre przepełnienie buforu.

  • Podczas pracy z dokumentami XML wprowadzanej należy sprawdzić wszystkie dane ze schematem.

  • Budowanie nigdy nie Transact-SQL instrukcji bezpośrednio z danych wejściowych użytkownika.

  • Użyj procedury przechowywane do sprawdzania poprawności danych wejściowych użytkownika.

  • W środowiskach rozwią zaniu wszystkie dane powinny zostać zatwierdzone przed dopuszczenia do strefy zaufanych.Dane, które nie przeszły pomyślnie procesu sprawdzania poprawności powinien zostać odrzucony i błąd powinny być zwrócone do poprzedniego poziomu.

  • Implementuje wiele warstw sprawdzania poprawności.Środki bezpieczeństwa stosowane wobec swobodnie złośliwi użytkownicy mogą być nieskuteczne przed atakami ustalone.Lepszą praktyką jest sprawdzanie poprawności danych wejściowych w interfejs użytkownika i na wszystkich kolejnych punktów, w którym przecina ona granice zaufania.

    Na przykład sprawdzanie poprawności danych w aplikacji po stronie klient można zapobiec iniekcji prosty skrypt.Jednak jeśli następnej warstwy zakłada, że jej wprowadzania została już sprawdzona, złośliwy użytkownik, który można pominąć klient można mają nieograniczony dostęp do systemu.

  • Złączanie nigdy nie jest sprawdzana poprawność danych wejściowych użytkownika.Ciąg łączenie jest podstawowy punkt wejścia na uruchomienie skryptu.

  • Nie akceptuje następujące ciągi w polach, z których może być skonstruowane nazw plików: AUX, ZEGAR$, COM1 COM8 CON, CONFIG$ LPT1 do LPT8, NUL i PRN.

Gdy użytkownik może odrzucić wprowadzania, która zawiera następujących znaków.

Znak wejściowy

Znaczenie w języku Transact-SQL

;

Kwerendy ogranicznik.

'

Ogranicznik ciąg danych.

--

Ogranicznik komentarz.

/* ...*/

Ograniczniki komentarza.Tekst między / * i * / nie jest sprawdzane przez serwer.

xp_

Używany na początku nazwy rozszerzone wykazu procedury przechowywane, jak na przykład xp_cmdshell.

Parametry SQL typ palety

Parametry kolekcja w SQL Server zawiera kontrola typów i długość sprawdzania poprawności.Jeśli używasz Parametry kolekcja wejściowych jest traktowana jako wartość literału zamiast kodu wykonywalnego.Dodatkową zaletą korzystania z Parametry kolekcja jest można wymusić typ i długość sprawdza.Wartości spoza zakres uruchomią wyjątek.Pokazuje poniższy fragment kodu za pomocą Parametry kolekcja:

SqlDataAdapter myCommand = new SqlDataAdapter("AuthorLogin", conn);
myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;
SqlParameter parm = myCommand.SelectCommand.Parameters.Add("@au_id",
     SqlDbType.VarChar, 11);
parm.Value = Login.Text;

W tym przykładzie @au_id parametr jest traktowany jako wartości literału zamiast jako kod wykonywalny.Ta wartość jest sprawdzany typ i długość.Jeśli wartość @au_id nie jest zgodne z określonego typu i ograniczenia długości wyjątek będzie generowany.

Procedury przechowywane za pomocą sparametryzowanych wprowadzania

Procedury przechowywane mogą być podatna na iniekcje SQL korzystania z wprowadzania niefiltrowanym.Na przykład poniższy kod jest zagrożony:

SqlDataAdapter myCommand = 
new SqlDataAdapter("LoginStoredProcedure '" + 
                               Login.Text + "'", conn);

Jeśli używasz procedury przechowywane, należy używać parametrów jako danych wejściowych.

Kolekcja parametrów za pomocą Dynamic SQL

Jeśli nie można użyć procedur przechowywanych, można nadal używać parametrów, jak pokazano w poniższym przykładzie kodu:

SqlDataAdapter myCommand = new SqlDataAdapter(
"SELECT au_lname, au_fname FROM Authors WHERE au_id = @au_id", conn);
SQLParameter parm = myCommand.SelectCommand.Parameters.Add("@au_id", 
                        SqlDbType.VarChar, 11);
Parm.Value = Login.Text;

Filtrowanie danych wejściowych

Filtrowanie danych wejściowych może być również pomocne w ochronie przed iniekcją SQL przez usunięcie znaków escape.Jednak ze względu na dużą liczbę znaków, które mogą powodować problemy, to nie jest niezawodne obrony.Następujący przykład wyszukuje Ogranicznik ciąg znaków.

private string SafeSqlLiteral(string inputSQL)
{
  return inputSQL.Replace("'", "''");
}

Podobnie jak klauzul

Należy zauważyć, że jeśli używasz klauzula LIKE wieloznacznych nadal muszą mieć zmienione znaczenie za:

s = s.Replace("[", "[[]");
s = s.Replace("%", "[%]");
s = s.Replace("_", "[_]");

Przeglądając kod iniekcji SQL

Cały kod wywołuje EXECUTE Szefowie, należy przejrzeć lub sp_executesql.Podobna do następującej kwerendy umożliwia identyfikowanie procedur, które zawierają instrukcje te.Ta kwerenda sprawdza 1, 2, 3 lub 4 spacji po wyrazach wykonywanie lub EXEC.

SELECT object_Name(id) FROM syscomments

WHERE UPPER(text) LIKE '%EXECUTE (%'

OR UPPER(text) LIKE '%EXECUTE  (%'

OR UPPER(text) LIKE '%EXECUTE   (%'

OR UPPER(text) LIKE '%EXECUTE    (%'

OR UPPER(text) LIKE '%EXEC (%'

OR UPPER(text) LIKE '%EXEC  (%'

OR UPPER(text) LIKE '%EXEC   (%'

OR UPPER(text) LIKE '%EXEC    (%'

OR UPPER(text) LIKE '%SP_EXECUTESQL%'

Parametry QUOTENAME() i REPLACE() zawijania

W każdej wybranej procedura składowana, sprawdź, czy wszystkie zmienne, które są używane w dynamicznych Transact-SQL są obsługiwane poprawnie.Dane, które pochodzą z parametrów wejściowych procedura składowana lub który jest odczytywany z tabela powinny być zapakowane w QUOTENAME() lub REPLACE().Należy pamiętać, że wartość zmiennej @ przekazanego do QUOTENAME() jest sysname, i może zawierać maksymalnie 128 znaków.

@ zmiennej

Zalecane otoki

Nazwa zabezpieczany

QUOTENAME (zmiennej @)

Ciąg ≤ 128 znaków.

QUOTENAME (@ zmiennej, '''')

Ciąg znaków z > 128 znaków

ZAMIEŃ (zmiennej @, "", "'''')

Korzystając z tej techniki, instrukcja SET mogą podlegać przeglądowi w następujący sposób:

--Before:

SET @temp = N'select * from authors where au_lname='''

+ @au_lname + N''''

--After:

SET @temp = N'select * from authors where au_lname='''

+ REPLACE(@au_lname,'''','''''') + N''''

Wtrysk włączane przez obcięcie danych

Wszelkie dynamicznie Transact-SQL przypisane do zmiennej zostanie obcięty, jeśli jest większy niż buforu przydzielanego dla tej zmiennej.Osoba atakująca może wymusić obcinania instrukcja przekazując nieoczekiwanie długie ciągi procedura składowana można manipulować wynik.Na przykład procedura składowana, która jest tworzona przez następujący skrypt jest zagrożony iniekcji włączane przez obcinania.

CREATE PROCEDURE sp_MySetPassword

@loginname sysname,

@old sysname,

@new sysname

AS

-- Declare variable.

-- Note that the buffer here is only 200 characters long.

DECLARE @command varchar(200)

-- Construct the dynamic Transact-SQL.

-- In the following statement, we need a total of 154 characters

-- to set the password of 'sa'.

-- 26 for UPDATE statement, 16 for WHERE clause, 4 for 'sa', and 2 for

-- quotation marks surrounded by QUOTENAME(@loginname):

-- 200 – 26 – 16 – 4 – 2 = 154.

-- But because @new is declared as a sysname, this variable can only hold

-- 128 characters.

-- We can overcome this by passing some single quotation marks in @new.

SET @command= 'update Users set password=' + QUOTENAME(@new, '''') + ' where username=' + QUOTENAME(@loginname, '''') + ' AND password = ' + QUOTENAME(@old, '''')

-- Execute the command.

EXEC (@command)

GO

Przekazując 154 znaków do buforu 128 znaków, osoba atakująca, której zestaw nowe hasło dla sa bez znajomości starego hasła.

EXEC sp_MySetPassword 'sa', 'dummy', '123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012'''''''''''''''''''''''''''''''''''''''''''''''''''

Z tego powodu należy użyć dużego buforu dla zmiennej polecenia lub bezpośrednio wykonywania dynamicznej Transact-SQL wewnątrz instrukcja wykonać.

QUOTENAME(@variable, '''') podczas obcinania i REPLACE() są używane

Ciągi, które są zwracane przez QUOTENAME() i REPLACE() zostanie obcięty dyskretnie jeżeli przekraczają przestrzeń, która jest przydzielona.procedura składowana, która jest tworzona w poniższym przykładzie pokazano, co może się zdarzyć.

CREATE PROCEDURE sp_MySetPassword

@loginname sysname,

@old sysname,

@new sysname

AS

-- Declare variables.

DECLARE @login sysname

DECLARE @newpassword sysname

DECLARE @oldpassword sysname

DECLARE @command varchar(2000)

-- In the following statements, the data stored in temp variables

-- will be truncated because the buffer size of @login, @oldpassword,

-- and @newpassword is only 128 characters, but QUOTENAME() can return

-- up to 258 characters.

SET @login = QUOTENAME(@loginname, '''')

SET @oldpassword = QUOTENAME(@old, '''')

SET @newpassword = QUOTENAME(@new, '''')

-- Construct the dynamic Transact-SQL.

-- If @new contains 128 characters, then @newpassword will be '123... n

-- where n is the 127th character.

-- Because the string returned by QUOTENAME() will be truncated,

-- it can be made to look like the following statement:

-- UPDATE Users SET password ='1234. . .[127] WHERE username=' -- other stuff here

SET @command = 'UPDATE Users set password = ' + @newpassword

+ ' where username =' + @login + ' AND password = ' + @oldpassword;

-- Execute the command.

EXEC (@command)

GO

Dlatego będzie następująca instrukcja zestaw hasła wszystkich użytkowników do wartości, która została przekazana w poprzednim kodzie.

EXEC sp_MyProc '--', 'dummy', '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678'

Przekroczenie miejsca przydzielonego buforu podczas korzystania z REPLACE() można wymusić ciąg obcinania.procedura składowana, która jest tworzona w poniższym przykładzie pokazano, co może się zdarzyć.

CREATE PROCEDURE sp_MySetPassword

@loginname sysname,

@old sysname,

@new sysname

AS

-- Declare variables.

DECLARE @login sysname

DECLARE @newpassword sysname

DECLARE @oldpassword sysname

DECLARE @command varchar(2000)

-- In the following statements, data will be truncated because

-- the buffers allocated for @login, @oldpassword and @newpassword

-- can hold only 128 characters, but QUOTENAME() can return

-- up to 258 characters.

SET @login = REPLACE(@loginname, '''', '''''')

SET @oldpassword = REPLACE(@old, '''', '''''')

SET @newpassword = REPLACE(@new, '''', '''''')

-- Construct the dynamic Transact-SQL.

-- If @new contains 128 characters, @newpassword will be '123... n

-- where n is the 127th character.

-- Because the string returned by QUOTENAME() will be truncated, it

-- can be made to look like the following statement:

-- UPDATE Users SET password='1234…[127] WHERE username=' -- other stuff here

SET @command= 'update Users set password = ''' + @newpassword + ''' where username='''

+ @login + ''' AND password = ''' + @oldpassword + '''';

-- Execute the command.

EXEC (@command)

GO

Zgodnie z QUOTENAME(), można uniknąć obcięcia ciąg przez REPLACE() przez deklarowania zmiennych tymczasowych, które są wystarczająco duże, we wszystkich przypadkach.Jeśli to możliwe, należy wywołać QUOTENAME() lub REPLACE() bezpośrednio wewnątrz dynamicznej Transact-SQL.W przeciwnym razie wymagany rozmiar buforu można obliczyć w następujący sposób.Dla @outbuffer = QUOTENAME(@input), rozmiar @outbuffer powinien być 2*(len(@input)+1). When you use REPLACE() and doubling quotation marks, as in the previous example, a buffer of 2*len(@input) is enough.

Następujące obliczenie obejmuje wszystkie przypadki:

While len(@find_string) > 0, required buffer size =

round(len(@input)/len(@find_string),0) * len(@new_string)

+ (len(@input) % len(@find_string))

Obcięcie podczas QUOTENAME(@variable, ']') jest używany

Obcięcie może wystąpić podczas nazwę SQL Server zabezpieczany są przekazywane do instrukcji, które formularz QUOTENAME(@variable, ']').Poniższy przykład przedstawia to.

CREATE PROCEDURE sp_MyProc

@schemaname sysname,

@tablename sysname,

AS

-- Declare a variable as sysname. The variable will be 128 characters.

-- But @objectname actually must allow for 2*258+1 characters.

DECLARE @objectname sysname

SET @objectname = QUOTENAME(@schemaname)+'.'+ QUOTENAME(@tablename)

-- Do some operations.

GO

Kiedy są konkatenację wartości typu sysname, należy używać zmiennych tymczasowych przewyższającym maksymalnie 128 znaków na wartości.Jeśli to możliwe, wywołać QUOTENAME() bezpośrednio wewnątrz dynamicznej Transact-SQL.W przeciwnym razie można obliczyć wymagany rozmiar buforu, jak wyjaśniono w poprzedniej sekcji.