Czy parametry naprawdę wystarczają, aby zapobiec wstrzyknięciom Sql?

83

Przekazywałem zarówno moim kolegom, jak i tutaj w SO, zalety używania parametrów w zapytaniach SQL, zwłaszcza w aplikacjach .NET. Posunąłem się nawet do obietnicy, że dają im odporność na ataki typu SQL injection.

Ale zaczynam się zastanawiać, czy to naprawdę prawda. Czy istnieją znane ataki polegające na iniekcji SQL, które zakończą się sukcesem w przypadku sparametryzowanego zapytania? Czy możesz na przykład wysłać napis, który powoduje przepełnienie bufora na serwerze?

Istnieją oczywiście inne kwestie, które należy wziąć pod uwagę, aby upewnić się, że aplikacja internetowa jest bezpieczna (np. Oczyszczanie danych wejściowych użytkownika i tym podobne), ale teraz myślę o wstrzyknięciach SQL. Szczególnie interesują mnie ataki na MsSQL 2005 i 2008, ponieważ są to moje podstawowe bazy danych, ale wszystkie bazy danych są interesujące.

Edycja: Aby wyjaśnić, co mam na myśli przez parametry i sparametryzowane zapytania. Używając parametrów, mam na myśli używanie „zmiennych” zamiast budowania zapytania sql w ciągu.
Więc zamiast tego robić:

SELECT * FROM Table WHERE Name = 'a name'

My to robimy:

SELECT * FROM Table WHERE Name = @Name

a następnie ustaw wartość parametru @Name w obiekcie zapytania / polecenia.

Rune Grimstad
źródło
powinniśmy wyjaśnić, co oznaczają parametry (jak wskazał Jonathan Leffler) - myślałem o parametrach procedury składowanej, ale są też? parmy i {0} parmy ...
Steven A. Lowe
O wiele łatwiej powiedzieć, że nie używamy konkatenacji do tworzenia zapytania.
Ponieważ tag to asp.net, zakładam, że tworzysz aplikacje internetowe. W takim razie warto też zadbać o ataki XSS, a może i inne
Spikolynn.

Odpowiedzi:

50

Aby zapobiec zastrzykom, wystarczą symbole zastępcze . Nadal możesz być otwarty na przepełnienia bufora, ale jest to zupełnie inny rodzaj ataku niż wstrzyknięcie SQL (wektor ataku nie byłby składnią SQL, ale binarny). Ponieważ wszystkie przekazane parametry zostaną odpowiednio zmienione, atakujący nie może w żaden sposób przekazać danych, które będą traktowane jak „aktywny” kod SQL.

Nie możesz używać funkcji wewnątrz symboli zastępczych i nie możesz używać symboli zastępczych jako nazw kolumn lub tabel, ponieważ są one chronione i cytowane jako literały ciągu.

Jeśli jednak użyjesz parametrów jako części konkatenacji ciągów wewnątrz zapytania dynamicznego, nadal jesteś narażony na iniekcję, ponieważ twoje ciągi nie zostaną zmienione, ale będą dosłowne. Używanie innych typów parametrów (takich jak liczba całkowita) jest bezpieczne.

To powiedziawszy, jeśli używasz danych wejściowych do ustawiania wartości czegoś podobnego security_level, ktoś może po prostu stać się administratorami w twoim systemie i mieć swobodę dla wszystkich. Ale to tylko podstawowa walidacja danych wejściowych i nie ma nic wspólnego z iniekcją SQL.

Adam Bellaire
źródło
Kluczową kwestią jest zrozumienie kwestii, jaką porusza odpowiedź Steve'a Lowe'a, wskazana również w artykule @mikekidder cytuje - trzeba być ostrożnym wszędzie tam, gdzie jest Dynamic SQL, czy to w aplikacji, czy na serwerze. Dynamiczny SQL jest niebezpieczny - ale można go zabezpieczyć.
Jonathan Leffler
„atakujący nie może w żaden sposób przekazać danych, które będą traktowane jak„ żywy ”kod SQL”. - To nie jest do końca prawdą, zobacz przykłady poniżej.
Booji Boy
Wszystkie poniższe przykłady definiują „sparametryzowane zapytanie” jako oznaczenie kodu SQL akceptującego parametry. Normalna definicja to zapytanie, które korzysta z kolekcji parametrów DBMS. Poza błędem DBMS ta druga technika zapobiega iniekcji SQL.
HTTP 410
2
Przeczytałem każdy link. Proszę zacytować dowolny link, który odnosi się do działającego ataku polegającego na iniekcji przeciwko kolekcji DBMS Parameters. Rzeczywiście, link, który opublikowałeś, odnosi się konkretnie do tego podejścia jako pokonania iniekcji SQL (zobacz sekcję „Używanie parametrów SQL bezpiecznych dla typów”).
HTTP 410
Cześć! Czy możesz podać link do gramatyki Oracle SQL lub czegoś podobnego, aby udowodnić tę odpowiedź. Rozumiem to i absolutnie się z tobą zgadzam, ale wspaniale byłoby mieć oficjalny link do dokumentacji, gramatyki itp. BestRegards, Raimbek
Raimbek Rakhimbek
13

Nie, nadal istnieje ryzyko wstrzyknięcia SQL za każdym razem, gdy interpolujesz niezatwierdzone dane do zapytania SQL.

Parametry zapytania pomagają uniknąć tego ryzyka, oddzielając wartości literałów od składni SQL.

'SELECT * FROM mytable WHERE colname = ?'

To dobrze, ale istnieją inne cele interpolacji danych do dynamicznego zapytania SQL, które nie mogą używać parametrów zapytania, ponieważ nie jest to wartość SQL, ale nazwa tabeli, nazwa kolumny, wyrażenie lub inna składnia.

'SELECT * FROM ' + @tablename + ' WHERE colname IN (' + @comma_list + ')'
' ORDER BY ' + @colname'

Nie ma znaczenia, czy używasz procedur składowanych, czy wykonujesz dynamiczne zapytania SQL bezpośrednio z kodu aplikacji. Ryzyko wciąż istnieje.

Środkiem zaradczym w takich przypadkach jest zatrudnienie FIEO w razie potrzeby:

  • Filtruj dane wejściowe: sprawdź, czy dane wyglądają jak prawidłowe liczby całkowite, nazwy tabel, nazwy kolumn itp. Przed ich interpolacją.

  • Wyjście Escape: w tym przypadku „wyjście” oznacza wprowadzenie danych do zapytania SQL. Używamy funkcji do transformacji zmiennych używanych jako literały łańcuchowe w wyrażeniu SQL, tak aby cudzysłowy i inne znaki specjalne wewnątrz ciągu były chronione przed ucieczką. Powinniśmy również używać funkcji do przekształcania zmiennych, które będą używane jako nazwy tabel, nazw kolumn itp. Jeśli chodzi o inną składnię, jak dynamiczne zapisywanie całych wyrażeń SQL, jest to bardziej złożony problem.

Bill Karwin
źródło
12

Wydaje się, że w tym wątku jest pewne zamieszanie co do definicji „sparametryzowanego zapytania”.

  • SQL, taki jak zapisany proces, który akceptuje parametry.
  • SQL, który jest wywoływany przy użyciu kolekcji DBMS Parameters.

Biorąc pod uwagę poprzednią definicję, wiele linków wskazuje na działające ataki.

Ale „normalna” definicja to ta druga. Biorąc pod uwagę tę definicję, nie znam żadnego ataku SQL injection, który zadziała. Nie oznacza to, że takiego nie ma, ale jeszcze go nie widziałem.

Z komentarzy nie wyrażam się wystarczająco jasno, więc mam nadzieję, że oto przykład, który będzie jaśniejszy:

To podejście jest otwarte dla iniekcji SQL

exec dbo.MyStoredProc 'DodgyText'

To podejście nie jest otwarte dla iniekcji SQL

using (SqlCommand cmd = new SqlCommand("dbo.MyStoredProc", testConnection))
{
    cmd.CommandType = CommandType.StoredProcedure;
    SqlParameter newParam = new SqlParameter(paramName, SqlDbType.Varchar);
    newParam.Value = "DodgyText";
    .....
    cmd.Parameters.Add(newParam);
    .....
    cmd.ExecuteNonQuery();
}
HTTP 410
źródło
Czy możesz wyjaśnić, co masz na myśli, mówiąc o kolekcji DBMS Parameters w przeciwieństwie do procedury, która akceptuje parametry?
Rune Grimstad
Rune, przeczytaj sekcję „Użyj parametrów SQL bezpiecznych dla typów” tego łącza: msdn.microsoft.com/en-us/library/ms161953.aspx
HTTP 410,
Odpowiedziałem na pierwotne pytanie Rune, zanim zostało zmienione wraz z aktualizacją.
mikekidder
Przeczytałem i ponownie przeczytałem ten artykuł msdn na temat wtrysku sql i nadal nie widzę różnicy między parametrami, które przyjmuje procedura składowana, a parametrami pobieranymi przez dynamiczne zapytanie. Pomijając fakt, że zapytania dynamiczne są dynamiczne. Nadal musisz powiązać parametry, prawda?
Rune Grimstad
To wiązanie robi różnicę. Jeśli bezpośrednio wywołujesz zapisaną procedurę z parametrami, nie jest wykonywane żadne filtrowanie danych wejściowych. Ale jeśli utworzysz powiązanie (na przykład) przy użyciu kolekcji parametrów SqlCommand w .NET, wszystkie parametry zostaną przefiltrowane i traktowane jako zwykły tekst.
HTTP 410
10

każdy parametr sql typu string (varchar, nvarchar itp.), który jest używany do konstruowania dynamicznego zapytania, jest nadal podatny na ataki

w przeciwnym razie konwersja typu parametru (np. na int, decimal, date, itp.) powinna wyeliminować wszelkie próby wprowadzenia sql przez parametr

EDYCJA: przykład, gdzie parametr @ p1 ma być nazwą tabeli

create procedure dbo.uspBeAfraidBeVeryAfraid ( @p1 varchar(64) ) 
AS
    SET NOCOUNT ON
    declare @sql varchar(512)
    set @sql = 'select * from ' + @p1
    exec(@sql)
GO

Jeśli @ p1 zostanie wybrane z listy rozwijanej, jest to potencjalny wektor ataku sql-injection;

Jeśli @ p1 jest sformułowane programowo bez możliwości interwencji użytkownika, to nie jest to potencjalny wektor ataku typu sql-injection

Steven A. Lowe
źródło
Nie; chodzi o to, że ciąg przekazany do DBMS nie jest częścią instrukcji SQL. Dlatego wartość w łańcuchu nie ma znaczenia dla interpretacji SQL - tylko dla wartości, do których odwołuje się SQL.
Jonathan Leffler
Tak też widzę parametry. Mają zapobiec temu problemowi.
Rune Grimstad
2
Steven ma rację, jeśli na przykład przekazujesz ciąg do sp, który używa go do uruchomienia czegoś takiego jak sp_executeSql (serwer sql), to nadal masz ryzyko wstrzyknięcia sql.
alexmac
@Steven: to nie jest parametr SQL; musiałbyś mieć symbol zastępczy (znak zapytania) zamiast konkatenacji ciągów. SQL nie pozwala na określenie nazwy tabeli za pomocą symbolu zastępczego. To jest czysta luka w zabezpieczeniach typu SQL injection - pierwotny problem.
Jonathan Leffler
@Steven: być może termin „parametr” był zbyt często przeciążany. : D
Jonathan Leffler
6

Przepełnienie buforu nie jest iniekcją SQL.

Sparametryzowane zapytania gwarantują bezpieczeństwo przed iniekcją SQL. Nie gwarantują, że na twoim serwerze SQL nie będzie możliwości exploitów w postaci błędów, ale nic tego nie gwarantuje.

Blorgbeard wyszedł
źródło
2

Twoje dane nie są bezpieczne, jeśli używasz dynamicznego sql w jakimkolwiek kształcie lub formie, ponieważ uprawnienia muszą być na poziomie tabeli. Tak, ograniczyłeś typ i ilość ataku iniekcyjnego z tego konkretnego zapytania, ale nie ograniczyłeś dostępu, jaki użytkownik może uzyskać, jeśli znajdzie drogę do systemu, i jesteś całkowicie podatny na dostęp dla użytkowników wewnętrznych, którzy mają dostęp do tego, czego nie powinni w celu popełnienia oszustwa lub kradzieży danych osobowych w celu sprzedaży. Dynamiczny SQL dowolnego typu to niebezpieczna praktyka. Jeśli używasz niedynamicznych przechowywanych procesów, możesz ustawić uprawnienia na poziomie procesu i żaden użytkownik nie może zrobić nic poza tym, co jest zdefiniowane przez proces (z wyjątkiem oczywiście administratorów systemu).

HLGEM
źródło
więc lekcja jest taka, że ​​jeśli musisz używać dynamicznego sql, rób to tylko wewnątrz procedury składowanej. +1 dobra rada!
Steven A. Lowe
1
Nie - dynamiczny SQL w przechowywanych procesach nadal może wprowadzać wady iniekcji SQL, interpolując niezatwierdzone dane do dynamicznego zapytania.
Bill Karwin
Nie, lekcja tutaj jest taka, aby nigdy nie używać dynamicznego
SQl
@HLGEM - racja, a samochody biorą udział w wypadkach drogowych, więc nigdy nie powinniśmy ich używać.
Bill Karwin
Jednak dynamiczny SQL w przechowywanym procencie działa (domyślnie) za pozwoleniem wywołującego, a nie statyczny SQL, który działa za zgodą właściciela przechowywanego proc. To ważne rozróżnienie.
HTTP 410
1

Istnieje możliwość, że przechowywany proces będzie podatny na specjalne typy iniekcji SQL poprzez przepełnienie / obcięcie, zobacz: Wstrzykiwanie włączone przez obcięcie danych tutaj:

http://msdn.microsoft.com/en-us/library/ms161953.aspx

Booji Boy
źródło
Jeśli szczegółowo przeczytasz artykuł, zobaczysz, że użycie kolekcji parametrów programu SQL Server zapobiega temu atakowi. I to jest normalna definicja "sparametryzowanego zapytania" - używa kolekcji Parameters DBMS.
HTTP 410
1

Pamiętaj tylko, że za pomocą parametrów możesz łatwo zapisać ciąg lub powiedzieć nazwę użytkownika, jeśli nie masz żadnych zasad, "); porzuć użytkowników tabeli; -"

To samo w sobie nie spowoduje żadnej szkody, ale lepiej wiesz, gdzie i jak ta data jest używana w dalszej części aplikacji (np. Przechowywana w pliku cookie, pobierana później w celu wykonania innych czynności.

nr
źródło
1

Możesz na przykład uruchomić dynamiczny sql

DECLARE @SQL NVARCHAR(4000);
DECLARE @ParameterDefinition NVARCHAR(4000);

SELECT  @ParameterDefinition = '@date varchar(10)'

SET @SQL='Select CAST(@date AS DATETIME) Date'

EXEC sp_executeSQL @SQL,@ParameterDefinition,@date='04/15/2011'
Mohamed Abbas
źródło