Czy mogę chronić się przed SQL Injection poprzez unikanie pojedynczych cudzysłowów i otaczających danych wejściowych użytkownika za pomocą pojedynczych cudzysłowów?

Zdaję sobie sprawę, że parametryzowane zapytania SQL to optymalny sposób na dezynfekcję danych wejściowych użytkownika podczas budowania zapytań zawierających dane wejściowe użytkownika, ale zastanawiam się, co jest złego w pobieraniu danych wejściowych użytkownika i unikaniu pojedynczych cudzysłowów i otaczaniu całego łańcucha pojedynczymi cudzysłowami. Oto kod:

sSanitizedInput = "'" & Replace(sInput, "'", "''") & "'"

Każdy pojedynczy cudzysłów wprowadzony przez użytkownika jest zastępowany podwójnymi pojedynczymi cudzysłowami, co eliminuje możliwość kończenia łańcucha, więc wszystko inne, co może wpisać, takie jak średniki, znaki procentowe itp. będą częścią łańcucha znaków i nie będą faktycznie wykonywane jako część polecenia. Używamy Microsoft SQL Server 2000, dla którego wierzę, że pojedynczy cudzysłów jest jedynym ogranicznikiem łańcucha znaków i jedynym sposobem ucieczki od ogranicznika łańcucha, więc nie ma sposobu, aby wykonać cokolwiek, co użytkownik wpisuje.

Nie widzę sposobu na uruchomienie ataku SQL injection przeciwko temu, ale zdaję sobie sprawę, że gdyby był tak kuloodporny, jak mi się wydaje, ktoś inny by o tym pomyślał już i byłoby to powszechną praktyką. Moje pytanie brzmi: co jest nie tak z tym kodem? Czy ktoś zna sposób na atak SQL injection poza tą techniką sanityzacji? Przykładowy wkład użytkownika, który wykorzystuje tę technikę, byłby bardzo pomocny.

Aktualizacja:

Dziękuję wszystkim za odpowiedzi; prawie wszystkie informacje, na które natknąłem się w moich badaniach, pojawiły się gdzieś na tej stronie, co jest oznaką inteligencji i umiejętności ludzi, którzy poświęcili czas z ich pracowitych dni, aby pomóc mi z tym pytaniem.

Powodem, dla którego nie zaakceptowałem jeszcze żadnej z odpowiedzi, jest to, że nadal Nie wiem, jak skutecznie uruchomić atak SQL injection przeciwko temu kodowi. Kilka osób zasugerowało, że odwrotny ukośnik ucieknie z jednego cytatu i pozostawi drugi, aby zakończyć łańcuch tak, że reszta łańcucha zostanie wykonana jako część polecenia SQL, i zdaję sobie sprawę, że ta metoda będzie działać, aby wstrzyknąć SQL do bazy danych mySQL, ale w MS SQL 2000 jedynym sposobem (który udało mi się znaleźć) ucieczki pojedynczego cytatu jest użycie innego pojedynczego qoute; ukośniki tego nie zrobią. I chyba że istnieje sposób na powstrzymanie ucieczki pojedynczego cudzysłowu, żadne z pozostałych danych wejściowych użytkownika nie zostanie wykonane, ponieważ wszystkie będą traktowane jako jeden ciąg ciągów ciągów ciągów ciągów ciągów ciągów ciągów ciągów ciągów ciągów ciągów ciągów ciągów ciągów ciągów ciągów ciągów ciągów ciągów ciągów ciągów ciągów ciągów ciągów.

Rozumiem, że są lepsze sposoby dezynfekcji danych wejściowych, ale naprawdę bardziej interesuje mnie dowiedzieć się, dlaczego metoda, którą podałem powyżej, nie zadziała. Jeśli ktoś zna jakieś specyficzny sposób zamontowania ataku SQL injection przeciwko tej metodzie sanityzacji chciałbym go zobaczyć.

Author: Uwe Keim, 2008-09-26

18 answers

Po pierwsze, to po prostu zła praktyka. Walidacja danych wejściowych jest zawsze konieczna, ale zawsze jest niepewna.
Co gorsza, Walidacja czarnej listy jest zawsze problematyczna, znacznie lepiej jest wyraźnie i ściśle zdefiniować, jakie wartości / formaty akceptujesz. Co prawda nie zawsze jest to możliwe - ale do pewnego stopnia zawsze trzeba to robić.
Kilka prac naukowych na temat temat:

Chodzi o to, że każda Czarna lista, którą wykonujesz (i zbyt permisywne białe listy), może zostać pominięta. Ostatni link do mojej pracy pokazuje sytuacje, w których nawet cytat można ominąć.

Nawet jeśli te sytuacje nie dotyczą ciebie, to i tak jest to zły pomysł. Co więcej, o ile Twoja aplikacja nie jest trywialnie mała, będziesz musiał poradzić sobie z konserwacją, a może pewną dozą zarządzania: jak zapewnić, że jej wykonanie jest prawidłowe, wszędzie przez cały czas?

Właściwy sposób:

  • Walidacja białej listy: Typ, Długość, format lub akceptowane wartości
  • jeśli chcesz czarnej listy, śmiało. Cytat jest dobrze, ale w kontekście innych łagodzeń.
  • Użyj obiektów poleceń i parametrów, aby przygotować i zweryfikować
  • wywołaj tylko zapytania parametryzowane.
  • jeszcze lepiej, używaj wyłącznie procedur składowanych.
  • Unikaj używania dynamicznego SQL i nie używaj konkatenacji łańcuchów do budowania zapytań.
  • Jeśli używasz SPs, możesz również ograniczyć uprawnienia w bazie danych do wykonywania tylko potrzebnego SPs, a nie uzyskiwać bezpośredniego dostępu do tabel.
  • można również łatwo zweryfikować, że cała baza kodowa uzyskuje dostęp do DB tylko za pośrednictwem SPs...
 82
Author: AviD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-17 17:53:51

Dobra, ta odpowiedź będzie odnosić się do aktualizacji pytania:

"Jeśli ktoś zna jakiś konkretny sposób na zamontowanie ataku SQL injection przeciwko tej metodzie sanityzacji, chciałbym go zobaczyć."

Teraz, poza ucieczką odwrotnego ukośnika MySQL - i biorąc pod uwagę, że mówimy o MSSQL, są w rzeczywistości 3 możliwe sposoby wstrzykiwania kodu SQL

Ssanitized Input = "'" & Replace(sInput, "'", """) & "'"

Weź pod uwagę, że nie wszystkie będą ważne przez cały czas i są bardzo zależne od Twojego rzeczywistego kodu wokół niego:

  1. second-order SQL Injection - jeśli zapytanie SQL zostanie przebudowane na podstawie danych pobranych z bazy danych Po ucieczce , dane są łączone bez sklejenia i mogą być pośrednio wstrzykiwane SQL. Zobacz
  2. String truncation - (nieco bardziej skomplikowane) - scenariusz jest to, że masz dwa pola, powiedzmy nazwę użytkownika i hasło, a SQL łączy oba. I oba pola (lub tylko pierwsze) mają twardy limit długości. Na przykład nazwa użytkownika jest ograniczona do 20 znaków. Powiedz, że masz ten kod:
username = left(Replace(sInput, "'", "''"), 20)

Następnie otrzymujesz nazwę użytkownika, unikalny, a następnie przycięty do 20 znaków. Problem tutaj - wpiszę swój cytat w 20 znak (np. po 19 a), a twój cytat uciekający zostanie przycięty (w 21 znak). Następnie SQL

sSQL = "select * from USERS where username = '" + username + "'  and password = '" + password + "'"

W połączeniu z powyższa Nieprawidłowa nazwa użytkownika spowoduje, że hasło będzie już poza cudzysłowami i będzie zawierać bezpośrednio ładunek.
3. Przemyt Unicode - w pewnych sytuacjach można przekazać znak wysokiego poziomu unicode, który wygląda jak cytat, ale nie jest - dopóki nie dotrze do bazy danych, gdzie nagle jest . Ponieważ nie jest to cytat, gdy go walidujesz, przejdzie to łatwo... Zobacz moją poprzednią odpowiedź po więcej szczegóły i link do oryginalnych badań.

 38
Author: AviD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-18 02:03:54

W skrócie: nigdy nie pytaj o siebie. Na pewno coś ci się stanie. Zamiast tego użyj parametryzowanych zapytań lub jeśli z jakiegoś powodu nie możesz tego zrobić, Użyj istniejącej biblioteki, która zrobi to za Ciebie. Nie ma powodu, żeby robić to samemu.

 27
Author: Nick Johnson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-26 12:51:17

Zdaję sobie sprawę, że to było dawno po zadaniu pytania, ale ..

Jednym ze sposobów na rozpoczęcie ataku na procedurę 'Cytuj argument' jest obcinanie łańcuchów. Zgodnie z MSDN, w SQL Server 2000 SP4 (i SQL Server 2005 SP1) zbyt długi ciąg będzie po cichu ścięty.

Gdy zacytujesz ciąg znaków, ciąg zwiększa się w rozmiarze. Każdy apostrof jest powtarzany. To może być następnie wykorzystane do wypychania części SQL poza bufor. Dzięki czemu można skutecznie przycinać części klauzuli where.

Byłoby to prawdopodobnie najbardziej przydatne w scenariuszu strony "administrator użytkownika", w którym można nadużywać instrukcji "aktualizacja", aby nie wykonywać wszystkich kontroli, które miało to zrobić.

Więc jeśli zdecydujesz się cytować wszystkie argumenty, upewnij się, że wiesz, co dzieje się z rozmiarami łańcuchów i dopilnuj, aby nie doszło do okrojenia.

Polecam korzystanie z parametrów. Zawsze. Chciałbym to wyegzekwować w bazie danych. A jako efekt uboczny, jesteś bardziej prawdopodobnie uzyskamy lepsze trafienia pamięci podręcznej, ponieważ więcej poleceń wygląda tak samo. (To z pewnością prawda na Oracle 8)

 17
Author: Jørn Jensen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-19 10:57:55

Input sanitiation to nie jest coś, co chcesz pół-ass. Użyj całego tyłka. Używaj wyrażeń regularnych na polach tekstowych. Spróbuj ustawić cyfry na odpowiedni typ numeryczny i Zgłoś błąd walidacji, jeśli nie zadziała. Bardzo łatwo jest wyszukiwać wzorce ataków w danych wejściowych, takie jak'--. Załóżmy, że wszystkie dane wejściowe od użytkownika są wrogie.

 8
Author: tom.dietrich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-26 12:51:02

Używałem tej techniki, gdy miałem do czynienia z funkcjonalnością 'advanced search', gdzie zbudowanie zapytania od zera było jedyną realną odpowiedzią. (Przykład: pozwala użytkownikowi wyszukiwać produkty w oparciu o nieograniczony zestaw ograniczeń atrybutów produktów, wyświetlając kolumny i ich dozwolone wartości jako kontrolki GUI, aby zmniejszyć próg uczenia się dla użytkowników.)

Sam w sobie jest bezpieczny AFAIK. Jak zauważył inny answer, być może będziesz musiał również poradzić sobie z ucieczką backspace (aczkolwiek nie przy przekazywaniu zapytania do SQL Server za pomocą ADO lub ADO.NET, przynajmniej-nie ręczę za wszystkie bazy danych czy technologie).

Problem polega na tym, że naprawdę musisz mieć pewność, które ciągi zawierają dane wejściowe użytkownika (zawsze potencjalnie złośliwe), a które są poprawnymi zapytaniami SQL. Jedną z pułapek jest użycie wartości z bazy danych - czy te wartości zostały pierwotnie dostarczone przez użytkownika? Jeśli tak, to i oni muszą uciec. Moją odpowiedzią jest próba odkażenia jak najdłużej (ale nie później!), podczas konstruowania zapytania SQL.

Jednak w większości przypadków Wiązanie parametrów jest drogą -- jest to po prostu prostsze.

 8
Author: Pontus Gagge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-26 12:51:34

To i tak zły pomysł, jak ci się wydaje.

A może coś w rodzaju ucieczki cytatu w łańcuchu, jak to: \ '

Twój zastąpienie spowoduje: \ "

Jeśli ukośnik odwrotny ucieka przed pierwszym cudzysłowem, to drugi cudzysłów kończy łańcuch.

 6
Author: WW.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-26 12:45:33

Prosta odpowiedź: to będzie działać czasami, ale nie cały czas. Chcesz używać walidacji białej listy na wszystkim, ale zdaję sobie sprawę, że nie zawsze jest to możliwe, więc jesteś zmuszony wybrać najlepszą czarną listę. Podobnie, chcesz używać sparametryzowanych przechowywanych procków w wszystkim, ale po raz kolejny, nie zawsze jest to możliwe, więc jesteś zmuszony używać sp_execute z parametrami.

Istnieją sposoby obejścia każdej użytecznej czarnej listy, którą możesz wymyślić (i niektóre whitelistów też).

Przyzwoity writeup jest tutaj: http://www.owasp.org/index.php/Top_10_2007-A2

Jeśli chcesz to zrobić jako szybkie rozwiązanie, aby dać ci czas na stworzenie prawdziwego, zrób to. Ale nie myśl, że jesteś bezpieczna.

 5
Author: Invalid Character,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-26 19:32:42

Są dwa sposoby, bez wyjątków, aby być bezpiecznym od SQL-Injection; przygotowane instrukcje lub prametryzowane procedury przechowywane.

 5
Author: olle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-29 18:50:27

Jeśli masz sparametryzowane zapytania, powinieneś używać ich przez cały czas. Wystarczy jedno zapytanie, aby prześlizgnąć się przez Sieć i twój DB jest zagrożony.

 4
Author: Kev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-26 12:49:21

Tak, to powinno działać aż ktoś uruchomi Ustaw QUOTED_IDENTIFIER OFF i użyje podwójnego cudzysłowu na Tobie.

Edit: nie jest to takie proste, jak nie zezwalanie złośliwemu użytkownikowi na wyłączenie podanych identyfikatorów:

Natywny klient SQL Server ODBC driver i natywny klient SQL Server OLE DB Provider dla SQL Server automatycznie ustawiają QUOTED_IDENTIFIER na ON podczas łączenia. Można to skonfigurować w źródłach danych ODBC, w atrybutach połączeń ODBC lub OLE DB właściwości połączenia. domyślna wartość SET QUOTED_IDENTIFIER jest wyłączona dla połączeń z aplikacji DB-Library.

Podczas tworzenia procedury składowanej, Ustawienia SET QUOTED_IDENTIFIER I SET ANSI_NULLS są przechwytywane i używane do kolejnych wywołań tej procedury składowanej .

SET QUOTED_IDENTIFIER również odpowiada ustawieniu QUOTED_IDENTIFIER bazy danych ALTER.

SET QUOTED_IDENTIFIER to set at parse time . Ustawienie w czasie parse oznacza, że jeśli instrukcja SET jest obecna w procedurze wsadowej lub składowanej, staje się skuteczna, niezależnie od tego, czy wykonanie kodu rzeczywiście osiągnie ten punkt; a instrukcja SET staje się skuteczna przed wykonaniem jakichkolwiek instrukcji.

Jest wiele sposobów, w jaki QUOTED_IDENTIFIER może być wyłączony bez Twojej wiedzy. Co prawda-to nie jest exploit broni dymiącej, którego szukasz, ale to dość duża powierzchnia ataku. Oczywiście, jeśli również uciekł podwójne cytaty - wtedy wracamy do punktu wyjścia. ;)

 4
Author: Mark Brackett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-21 13:41:17

Twoja obrona by się nie powiodła, gdyby:

  • zapytanie oczekuje liczby, a nie ciągu
  • istniały inne sposoby reprezentowania pojedynczego cudzysłowu, w tym:
    • sekwencja ucieczki, taka jak \039
    • znak unicode

(w tym drugim przypadku musiałoby to być coś, co zostało rozszerzone dopiero po wykonaniu wymiany)

 4
Author: AJ.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 13:53:16

Patrick, czy dodajesz pojedyncze cudzysłowy wokół wszystkich wejść, nawet liczbowych? Jeśli masz wejście numeryczne, ale nie umieszczasz wokół niego pojedynczych cudzysłowów, to masz ekspozycję.

 4
Author: Rob Kraft,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-14 20:01:32

Jaki brzydki kod to wszystko by było! Następnie clunky StringBuilder dla instrukcji SQL. Przygotowana metoda statement skutkuje znacznie czystszym kodem, a zalety SQL Injection są naprawdę miłym dodatkiem.

Również po co odkrywać koło?

 1
Author: JeeBee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-26 12:45:48

Zamiast zmieniać pojedynczy cytat na (co wygląda jak) dwa pojedyncze cytaty, dlaczego po prostu nie zmienić go na apostrof, cytat, lub usunąć go całkowicie?

Tak czy inaczej, to trochę kludge... zwłaszcza, gdy legalnie masz rzeczy (takie jak nazwy), które mogą używać pojedynczych cudzysłowów...

Uwaga: Twoja metoda zakłada również, że wszyscy pracujący nad twoją aplikacją zawsze pamiętają o wyczyszczeniu danych wejściowych, zanim trafią do bazy danych, co prawdopodobnie nie jest realistyczne przez większość czasu.

 1
Author: Kevin Fairchild,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-26 12:48:17

To może zadziałać, ale wydaje mi się trochę niepewne. Zalecałbym sprawdzenie, czy każdy łańcuch jest poprawny, testując go zamiast wyrażenia regularnego.

 0
Author: Rob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-26 12:45:14

Chociaż możesz znaleźć rozwiązanie, które działa dla ciągów znaków, dla predykatów numerycznych musisz również upewnić się, że są one przekazywane tylko w liczbach (proste sprawdzenie jest czy można je parsować jako int/double/decimal?).

To dużo dodatkowej pracy.

 0
Author: Joseph Daigle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-26 12:45:29

Tak, możesz, jeśli...

Po przestudiowaniu tematu, myślę, że wprowadzanie danych zgodnie z Twoją sugestią jest bezpieczne, ale tylko zgodnie z tymi zasadami:

  1. Nigdy nie pozwalasz, aby wartości tekstowe pochodzące od użytkowników stały się czymś innym niż literały łańcuchowe (tzn. unikaj podawania opcji konfiguracji: "wprowadź dodatkowe nazwy kolumn/wyrażenia SQL tutaj:"). Typy wartości inne niż ciągi znaków (liczby, daty, ...): przekonwertować je na ich natywne typy danych i dostarczyć rutynę dla SQL z każdy typ danych.

    • wyrażenia SQL są problematyczne do walidacji
  2. Albo używasz nvarchar/nchar kolumny (i przedrostek literał ciągu z N) lub wartości graniczne przechodzące do varchar/char kolumny tylko do znaków ASCII (np. wyjątek throw podczas tworzenia instrukcji SQL)

      W ten sposób unikniesz automatycznej konwersji apostrofów z CHAR(700) do CHAR (39) (i być może innych podobnych hacków Unicode)
  3. Ty zawsze sprawdzaj długość wartości, aby pasowała do rzeczywistej długości kolumny (wyjątek throw jeśli jest dłuższy)

      W SQL serverze istnieje możliwość obejścia błędu SQL rzuconego przy obcinaniu (co prowadzi do cichego obcinania).]}
  4. Zapewniasz, że SET QUOTED_IDENTIFIER jest zawsze ON

    • uwaga, jest on stosowany w czasie parse-time, tj. nawet w niedostępnych sekcjach kodu

Przestrzegając tych 4 punktów, powinieneś być bezpieczny. Jeśli naruszając którekolwiek z nich, otwiera się sposób na SQL injection.

 0
Author: miroxlav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-22 21:31:00