Udostępnij za pośrednictwem


SQL Injection

Na ataki, w której złośliwy kod jest wstawiany do ciągów, które później zostaną przekazane do wystąpienie jest iniekcji SQL SQL Server podczas analizowania i wykonywanie. Postępowanie konstruuje instrukcje SQL należy weryfikować dla iniekcją, ponieważ SQL Server będzie wykonywać wszystkie syntaktycznie prawidłowa kwerendy, które otrzymuje. Nawet sparametryzowana danych można manipulować przez wykwalifikowanych i oznaczany atakująca.

Formularz podstawowy iniekcji SQL składa się z bezpośrednie wstawianie kodu do zmiennych danych wprowadzonych przez użytkownika, które są tak łączone za pomocą poleceń SQL i są stosowane.Mniej bezpośredni atak injects destrukcyjnego kodu do ciągów, które są przeznaczone do przechowywania w tabela lub w postaci metadane.Gdy ciągi przechowywane później są tak łączone, w dynamiczny polecenia SQL, złośliwy kod jest wykonywany.

Proces iniekcji polega na przedwczesne zakończenie ciąg tekstowego i dołączanie nowego polecenia.Ponieważ wstawiony polecenia może mieć dodatkowe ciągi dołączana przed jego wykonaniem, the malefactor kończy wprowadzoną ciąg znacznik komentarza "-".Następny tekst są ignorowane w czasie wykonywania.

Poniższy skrypt zawiera proste iniekcji SQL.Skrypt tworzy kwerendę SQL poprzez konkatenację ustalonych ciągi znaków, łącznie 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, połączone przez skrypt jest podobny do następującego:

SELECT * FROM OrdersTable WHERE ShipCity = 'Redmond'

Jednak przyjmijmy, że użytkownik nie wprowadzi następujące czynności:

Redmond'; drop table OrdersTable--

W takim przypadek następującej kwerendy są montowane przez skrypt:

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

Średnik (;) oznacza koniec jednej kwerendy, a następnie rozpocznij innego.Podwójne łącznika (-) wskazuje, że reszta z bieżącego wiersza jest komentarz i powinny być ignorowane.Jeżeli zmodyfikowany kod są poprawne syntaktycznie, zostanie wykonane przez serwer.Kiedy SQL Server Ta instrukcja przetwarzania SQL Server Najpierw wybierz opcję wszystkie rekordy OrdersTable gdzie ShipCity jest Redmond. Następnie, SQL Server powoduje usunięcie OrdersTable.

Tak długo, jak wprowadzoną kod SQL jest syntaktycznie prawidłowa, manipulowanie nie można wykryć programowo.W związku z tym należy sprawdzić wszystkie dane wprowadzone przez użytkownika i dokładnie Przegląd kodu, który wykonuje polecenia SQL zbudowane na serwerze, którego używasz.W poniższych sekcjach w tym temacie opisano kodowania najważniejszych wskazówek.

Sprawdź poprawność wszystkich wprowadzania

Zawsze testując typu, długość, format i zakres sprawdzania poprawności danych wejściowych użytkownika.Podczas są wdrażania środków ostrożności przed złośliwych danych wejściowych, należy wziąć pod uwagę scenariuszy architektury i rozmieszczenia aplikacji.Należy pamiętać, że programów przeznaczonych do uruchamiania w bezpiecznym środowisku mogą być kopiowane do środowiska, które nie są bezpieczne.Najważniejsze wskazówki dotyczące należy rozważyć następujące wskazówki:

  • Sprawdź założeń rozmiar, typ lub zakres danych, które będą odbierane przez aplikację.Na przykład należy sprawdzić następujące oceny:

    • W jaki sposób będzie działać aplikacja Jeśli użytkownik errant lub złośliwy wprowadzi plików MPEG 10 megabajtów, gdy aplikacja oczekuje, że kod pocztowy?

    • W jaki sposób będzie działać aplikacja Jeśli instrukcja DROP tabela jest osadzony pole tekstowym?

  • Testowanie rozmiaru i dane typu danych wejściowych i wymusić odpowiednie ograniczenia.Może to zapobiec przekroczenia buforu zamierzonego.

  • Badanie zawartości zmiennych typu ciąg i akceptuje tylko wartości oczekiwane.Odrzucić wpisy zawierające dane binarne, sekwencje escape i znaków komentarza.To może pomóc w zapobieganiu iniekcji skryptu i mogą być chronione przed niektórych programów wykorzystujących luki w zabezpieczeniach przepełnienia buforu.

  • Podczas pracy z dokumentami XML, sprawdzenie poprawności wszystkich danych przed jego schemat, zostanie on wprowadzony.

  • Nigdy nie kompilacji Transact-SQL instrukcje bezpośrednio od użytkownika wprowadzania.

  • Sprawdzanie poprawności użytkownika dane wejściowe za pomocą procedur przechowywanych.

  • W środowiskach multitiered wszystkie dane powinny zostać zatwierdzone przed dopuszczenie do strefy zaufanych.Dane, które nie odpowiada wymaganiom procesu sprawdzania poprawności powinny być odrzucone, a do poprzedniego poziomu powinien być zwrócony błąd.

  • Implementuje wiele warstw sprawdzania poprawności.Środki ostrożności, jakie można podjąć przed swobodnie złośliwego użytkownika, może być nieefektywne od określonej osoby nieupoważnione.Lepsze praktyką jest sprawdzanie poprawności danych wejściowych w interfejs użytkownika i na wszystkich kolejnych punktów miejsca przecięcia jej obramowanie zaufania.

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

  • Nigdy nie złączyć danych wprowadzonych przez użytkownika, który nie jest sprawdzana.Konkatenacja ciągów to podstawowy punkt wejścia dla wstrzyknięcie skryptu.

  • Nie akceptują następujące ciągi w polach, z której mogą być skonstruowane nazw plików: AUX, CLOCK $, COM1 do COM8, CON, CONFIG $, LPT1 do LPT8, NUL i PRN.

Gdy użytkownik może odrzucić dane wejściowe, który zawiera następujące znaki.

Znak wejściowy

Znaczenie w języku Transact-SQL

;

Kwerendy ogranicznika.

'

Ogranicznik ciąg znaków danych.

--

Ogranicznika komentarza.

/* ...*/

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

xp_

Używane na początku nazwy rozszerzone wykazu procedury przechowywane, takie jak xp_cmdshell.

Użyj awaryjnego typu parametry SQL

The Parameters kolekcja in SQL Server provides kontrola typów and length validation. Jeśli używasz Parametry pobierania, wprowadzanie jest traktowany jak literał zamiast jako kod wykonywalny.Dodatkowych korzyści ze stosowania Parametry kolekcja jest, że można wymuszać typ i długość sprawdza.Wartości spoza zakres wyzwoli wyjątek.Poniższy fragment kodu zawiera przy użyciu 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 jak literał zamiast jako kod wykonywalny. Ta wartość jest sprawdzana pod kątem typu i długości.Jeśli wartość @au\_id nie jest zgodne z określonego typu i ograniczeń długości, będzie się wyjątek.

Sparametryzowana wprowadzania za pomocą procedur przechowywanych

Procedury przechowywane mogą być podatne na iniekcji SQL, gdy korzystają z plików niefiltrowanych dane wejściowe.Na przykład następujący kod jest zagrożona:

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

Jeśli używasz procedury przechowywane, należy używać parametrów ich dane wejściowe.

Należy użyć kolekcja Parameters dynamicznej SQL

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

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 wprowadzania

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

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

LIKE klauzule

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ądanie kodu dla iniekcją SQL

Należy przejrzeć cały kod, który wywołuje wykonać EXEC, lub sp_executesql.Za pomocą kwerendy podobny do następującego ułatwiające identyfikowanie procedur, które zawierają te instrukcje.Ta kwerenda sprawdza 1, 2, 3 lub 4 spacji po słowa wykonać 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 zawijania z QUOTENAME() i REPLACE()

W każdej wybranej procedura przechowywana, sprawdź, czy wszystkich zmiennych używanych w dynamicznych Transact-SQL są obsługiwane poprawnie. Dane, które pochodzą z parametrów wejściowych procedura przechowywana lub który jest odczytywany z tabela powinny być otoczona QUOTENAME() lub REPLACE().Należy pamiętać, że wartość @ zmiennej , które są przekazywane do QUOTENAME() jestnazwa_systemu, a ma maksymalną długość 128 znaków.

@ zmiennej

Zalecane otoki

Nazwa zabezpieczany

QUOTENAME)@ zmiennej)

Ciąg ≤ 128 znaków.

QUOTENAME)@ zmiennej, '' '')

Ciąg > więcej niż 128 znaków

ZAMIEŃ)@ zmiennej,)

Korzystając z tej techniki, instrukcja zestaw mogą zostać zmienione 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''''

Iniekcji włączone przez obcięcie danych

Wszelkie dynamiczne Transact-SQL przypisany do zmiennej zostanie obcięty, jeśli jest większe niż bufor, przydzielanych dla tej zmiennej. Osoba atakująca, która może wymusić obcinania instrukcja, przekazując nieoczekiwanie długich ciągów znaków do procedura przechowywana można manipulować wynik.Na przykład procedura przechowywana, która jest tworzony przez następujący skrypt jest zagrożony iniekcji włączone 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 na wykonać dynamiczne Transact-SQL wewnątrz instrukcja wykonać.

QUOTENAME(@variable, '''') podczas obcinania i użycia REPLACE()

Ciągi, które są zwracane przez QUOTENAME() i REPLACE() zostanie dyskretnie obcięty, jeśli przekroczą przestrzeń, która jest przydzielona.Procedura przechowywana, 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

W związku z tym następująca instrukcja zostanie ustawione hasła wszystkich użytkowników na wartość, która została przekazana w poprzednim kodzie.

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

Aby wymusić obcinania ciąg znaków, można powyżej miejsca przydzielonego buforu podczas korzystania z REPLACE().Procedura przechowywana, 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

Podobnie jak w przypadku 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 jest to możliwe, należy wywołać QUOTENAME() lub REPLACE() bezpośrednio wewnątrz dynamiczne Transact-SQL. W przeciwnym przypadku rozmiar buforu wymagany można obliczyć w następujący sposób.Dla @outbuffer = QUOTENAME(@input), rozmiar @outbuffer należy 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))

Gdy QUOTENAME(@variable, ']') obcinania Jest używany

Obcięcie może wystąpić, gdy nazwa SQL Server zabezpieczany jest przekazywany do instrukcji, które za pomocą formularza QUOTENAME(@variable, ']'). W poniższym przykładzie pokazano 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

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