Czy mogę zabezpieczyć się przed wstrzyknięciem kodu SQL, zapisując pojedyncze cudzysłowy i otaczając dane wejściowe użytkownika pojedynczymi cudzysłowami?


Rozumiem, że sparametryzowane zapytania SQL są najlepszym sposobem na wyczyszczenie danych wejściowych użytkownika podczas tworzenia zapytań zawierających dane wejściowe użytkownika, ale zastanawiam się, co jest złego w przyjmowaniu danych wejściowych użytkownika i unikaniu pojedynczych cudzysłowów i otaczaniu całego ciągu 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ść zakończenia linii, więc wszystko inne, co mogą wprowadzić, takie jak średniki, znaki procentu itp., Będzie częścią ciągu i nie zostanie wykonane jako część zespołu.
Używamy Microsoft SQL Server 2000, dla którego uważam, że pojedynczy cudzysłów jest jedynym separatorem ciągów i jedynym sposobem na uniknięcie tego znaku, więc nie ma możliwości wykonania czegokolwiek wprowadzonego przez użytkownika.
Nie widzę żadnego sposobu na przeprowadzenie ataku SQL injection przeciwko temu, ale rozumiem, że gdyby był tak kuloodporny, jak mi się wydaje, ktoś inny by o tym pomyślał i byłoby to powszechną praktyką.
Co jest nie tak z tym kodem? Czy istnieje sposób, aby atak polegający na wstrzyknięciu SQL przeszedł przez tę technikę leczenia? Bardzo pomocny byłby przykład danych wprowadzanych przez użytkownika, który wykorzystuje tę technikę.
UPDATE:
Nadal nie znam żadnego sposobu na skuteczne przeprowadzenie ataku SQL injection na ten kod. Kilka osób zasugerowało, że ukośnik odwrotny pominie jeden cudzysłów i pozostawi drugi na końcu ciągu, tak że reszta ciągu zostanie wykonana jako część polecenia SQL, i rozumiem, że ta metoda będzie działać do wstrzykiwania SQL do baza danych MySQL, ale w SQL Server 2000 jedynym sposobem (jaki mogłem znaleźć) na uniknięcie pojedynczego cudzysłowu jest użycie innego pojedynczego cudzysłowu; ukośniki odwrotne tego nie zrobią.
A jeśli nie ma sposobu na zatrzymanie zmiany znaczenia pojedynczego cudzysłowu, żadna z pozostałych danych wejściowych użytkownika nie zostanie wykonana, ponieważ wszystkie zostaną potraktowane jako jeden ciągły ciąg.
Rozumiem, że istnieją lepsze sposoby oczyszczenia wkładu, ale naprawdę jestem bardziej zainteresowany tym, dlaczego metoda, którą podałem powyżej, nie działa. Jeśli ktoś zna jakiś konkretny sposób przeprowadzenia ataku SQL injection przeciwko tej metodzie dezynfekcji, z chęcią przyjrzę się temu.
Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Po pierwsze, to po prostu zła praktyka. Walidacja danych wejściowych jest zawsze konieczna, ale zawsze budzi wątpliwości.

Co gorsza, sprawdzanie czarnej listy zawsze jest problematyczne, znacznie lepiej jest wyraźnie i ściśle określić, jakie wartości/formaty akceptujesz. Oczywiście nie zawsze jest to możliwe, ale do pewnego stopnia zawsze należy to robić.

Niektóre prace naukowe na ten temat:

Chodzi o to, że każdą czarną listę, którą tworzysz (i zbyt liberalne białe listy), można ominąć. Ostatni link do mojego artykułu pokazuje sytuacje, w których można obejść nawet ucieczkę cytatu.
Nawet jeśli te sytuacje Cię nie dotyczą, nadal jest to zły pomysł. Co więcej, jeśli Twoja aplikacja nie jest banalnie mała, będziesz musiał zająć się konserwacją i być może pewną dozą kontroli: jak upewnić się, że jest wykonywana dobrze, wszędzie i zawsze?
Prawidłowy sposób to:
  • Biała lista: typ, długość, format lub akceptowane wartości
  • Jeśli chcesz umieścić mnie na czarnej liście, śmiało. Uciekający cytat jest dobry, ale w kontekście innych złagodzeń.
  • Użyj obiektów poleceń i parametrów do przygotowania i walidacji
  • Wywołuj tylko zapytania sparametryzowane.
  • Jeszcze lepiej, używaj wyłącznie procedur składowanych.
  • Unikaj używania dynamicznego języka SQL i nie używaj konkatenacji ciągów do tworzenia zapytań.
  • Korzystając z usług SP, można również ograniczyć uprawnienia w bazie danych do wykonywania tylko wymaganych dostawców usług zamiast bezpośredniego dostępu do tabel.
  • możesz również łatwo sprawdzić, czy cała baza kodu ma dostęp do bazy danych tylko przez SP ...
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Ok, ta odpowiedź będzie dotyczyła aktualizacji pytania:

„Jeśli ktoś wie o jakimś konkretnym ataku typu mount i SQL injection przeciwko tej metodzie dezynfekcji, z przyjemnością go obejrzę”.

Teraz, oprócz ucieczki odwrotnym ukośnikiem MySQL - i biorąc pod uwagę, że tak naprawdę mówimy o MSSQL, istnieją właściwie 3 możliwe sposoby, aby nadal wstrzykiwać SQL do kodu

sSanitizedInput = "'" & amp; replace (sInput, "'", "" ") & amp;"' "

Należy pamiętać, że nie wszystkie będą ważne przez cały czas i są w dużym stopniu zależne od rzeczywistego kodu wokół nich:
  • Wstrzyknięcie SQL drugiego rzędu - jeśli zapytanie SQL jest przebudowywane na podstawie danych pobranych z bazy danych po przesiewie , dane są łączone bez zmiany znaczenia i mogą być pośrednio wprowadzane przez SQL. Widzieć
  • Obcinanie ciągów - (nieco bardziej złożony) - Scenariusz jest taki, że masz dwa pola, powiedz nazwę użytkownika i hasło, a SQL łączy je oba. A oba pola (lub tylko pierwsze) mają sztywny limit długości. Na przykład nazwa użytkownika jest ograniczona do 20 znaków. Powiedzmy, że masz ten kod:
username = left(Replace(sInput, "'", "''"), 20)
Otrzymujesz wtedy nazwę użytkownika, z ucieczką, a następnie skróconą do 20 znaków. Problem jest tutaj - wstawię swój cytat na 20. znak (np. Po 19 A), a Twój cytat ucieczki zostanie obcięty (na 21. znak). Następnie SQL
sSQL = "select * from USERS where username = '" + username + "' and password = '" + password + "'"

w połączeniu z wyżej wymienioną nieprawidłową nazwą użytkownika spowoduje to, że hasło zostanie już znalezione

na zewnątrz

cudzysłowy i będzie zawierać bezpośrednio ładunek.

Przemyt Unicode - w pewnych sytuacjach możliwe jest przesłanie wysokopoziomowego znaku Unicode

wygląda jak

jak cytat, ale

nie

jest taka - dopóki nie trafi do bazy danych, gdzie nagle

będzie
... Ponieważ to nie jest cytat, kiedy go zaznaczysz, przejdzie łatwo ... Zobacz moją poprzednią odpowiedź, aby uzyskać więcej informacji i link do oryginalnych badań.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Krótko mówiąc: nigdy nie próbuj uciekać od siebie. Na pewno coś zepsujesz. Zamiast tego użyj zapytań parametrycznych 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, aby robić to samemu.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Rozumiem, że minęło dużo czasu, odkąd zadano to pytanie, ale ...
Jednym ze sposobów rozpoczęcia ataku na procedurę „cytuj argument” jest obcięcie łańcucha.
Według MSDN w SQL Server 2000 SP4 (i SQL Server 2005 SP1) zbyt długi ciąg będzie na nim łatwy.
Kiedy cytujesz wiersz, rośnie on. Każdy apostrof jest powtarzany.
Można to następnie wykorzystać do wypchnięcia części kodu SQL z bufora. W ten sposób możesz skutecznie przyciąć części klauzuli where.
Byłoby to prawdopodobnie najbardziej przydatne w przypadku stron typu „administrator użytkowników”, na których można by nadużywać instrukcji „aktualizacja”, aby nie wykonywać wszystkich czynności sprawdzających, które powinien był wykonać.
Jeśli więc zdecydujesz się zacytować wszystkie argumenty, upewnij się, że wiesz, co się dzieje z rozmiarami linii i uważaj, aby nie doszło do obcięcia.
Poleciłbym wybrać opcje. Jest zawsze. Szkoda tylko, że nie mogę tego zrobić w bazie danych. Efektem ubocznym jest większe prawdopodobieństwo lepszych trafień w pamięci podręcznej, ponieważ więcej operatorów wygląda tak samo. (Z pewnością było to prawdą w przypadku Oracle 8)
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Użyłem tej techniki w przypadku funkcji „wyszukiwania zaawansowanego”, w której jedyną realną odpowiedzią było zbudowanie zapytania od zera. (Przykład: Pozwól użytkownikowi wyszukiwać produkty na podstawie nieograniczonego zestawu ograniczeń atrybutów produktu, wyświetlając kolumny i ich dozwolone wartości jako elementy sterujące GUI w celu zmniejszenia progu uczenia się dla użytkowników).
Sam w sobie jest bezpieczny AFAIK. Jednak, jak wskazał inny respondent, możesz również zająć się ucieczką wsteczną (chociaż nie podczas wysyłania zapytania do SQL Server za pomocą ADO lub ADO.NET, przynajmniej - nie mogę ręczyć za wszystkie bazy danych lub technologie).
Problem polega na tym, że naprawdę musisz mieć pewność, które wiersze zawierają dane wejściowe użytkownika (zawsze potencjalnie złośliwe), a które wiersze są prawidłowymi zapytaniami SQL. Jedną z pułapek jest to, że używasz wartości z bazy danych - czy te wartości zostały pierwotnie dostarczone przez użytkownika? Jeśli tak, to i oni muszą zostać zbawieni. Moja odpowiedź brzmi: staram się oczyścić jak najpóźniej (ale nie później!) Podczas budowania zapytania SQL.
Jednak w większości przypadków wiązanie parametrów jest właściwą drogą, jest po prostu łatwiejsze.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Sanitarne wejście nie jest czymś, co chcesz robić pół tyłka. Użyj całego swojego tyłka. Użyj wyrażeń regularnych w polach tekstowych. TryCast swoje cyfry na poprawny typ liczbowy i zgłoś błąd weryfikacji, jeśli to nie zadziała. Bardzo łatwo jest wyszukać wzorce ataków w danych wejściowych, takie jak „-. Załóżmy, że wszystkie dane wejściowe użytkownika są wrogie.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Można to zrobić na dwa sposoby, bez wyjątków, aby uchronić się przed iniekcją SQL; przygotowane instrukcje lub zalecane procedury składowane.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Jak się wydaje, to i tak zły pomysł.
Co powiesz na coś takiego jak unikanie cudzysłowu w ciągu takim jak ten: \ '
Twoja zamiana spowoduje: \ "
Jeśli ukośnik odwrotny zmienia znaczenie pierwszego cudzysłowu, to drugi cudzysłów kończy ciąg.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Prosta odpowiedź: czasami to zadziała, ale nie zawsze.
Czy chcesz użyć weryfikacji białej listy dla

Całkowity

co robisz, ale rozumiem, że nie zawsze jest to możliwe, dlatego jesteś zmuszony wybrać czarną listę z lepszym zgadywaniem. Podobnie chcesz użyć sparametryzowanych procesów przechowywanych w

wszystko

ale znowu, nie zawsze jest to możliwe, więc musisz użyć sp_execute z parametrami.
Istnieją sposoby na obejście każdej przydatnej czarnej listy, o której możesz pomyśleć (a także niektórych białych list).
Przyzwoity wpis jest tutaj:

http://www.owasp.org/index.php/Top_10_2007-A2
http://www.owasp.org/index.php/Top_10_2007-A2
Jeśli chcesz to zrobić szybko, aby mieć czas na znalezienie prawdziwego rozwiązania, zrób to. Ale nie myśl, że jesteś bezpieczny.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Patrick, czy dodajesz pojedyncze cudzysłowy wokół WSZYSTKICH danych wejściowych, nawet liczbowych? Jeśli masz dane numeryczne, ale nie umieszczasz wokół nich pojedynczych cudzysłowów, masz ekspozycję.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Jeśli masz sparametryzowane zapytania, musisz ich używać cały czas. Wystarczy jedno żądanie, aby przejść przez sieć, a Twoja baza danych jest zagrożona.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Tak, to powinno działać, dopóki ktoś nie zacznie

SET QUOTED_IDENTIFIER
http://msdn.microsoft.com/en-u ... .aspx
i nie używa podwójnego cudzysłowu na tobie.
Edycja: nie jest to tak łatwe, jak uniemożliwienie atakującemu wyłączenia identyfikatorów w cudzysłowie:

Sterownik ODBC klienta SQL Server Native Client i dostawca OLE DB dla klienta macierzystego programu SQL Server dla programu SQL Server automatycznie ustawia QUOTED_IDENTIFIER na ON po nawiązaniu połączenia. Można to skonfigurować w źródłach danych ODBC, atrybutach połączenia ODBC lub właściwościach połączenia OLE DB.

Domyślnie wartość parametru jest ustawiona na WYŁ. Do łączenia się z bazą danych bibliotek aplikacji.

Podczas tworzenia procedury składowanej parametry

SET QUOTED_IDENTIFIER i SET ANSI_NULLS są rejestrowane i używane do kolejnych wywołań tej procedury składowanej

.

SET QUOTED_IDENTIFIER odpowiada również parametrowi QUOTED_IDENTIFER bazy danych ALTER.

SET QUOTED_IDENTIFIER

ustawione podczas składni

analiza. Ustawienie podczas analizowania oznacza, że ​​jeśli instrukcja SET jest obecna w pakiecie lub procedurze składowanej, to działa niezależnie od tego, czy wykonanie kodu faktycznie osiągnie ten punkt; a instrukcja SET zaczyna obowiązywać przed wykonaniem jakichkolwiek instrukcji.

QUOTED_IDENTIFIER można wyłączyć na wiele sposobów bez Twojej wiedzy. Wprawdzie nie jest to dymiący exploit dla broni, którego szukasz, ale jest to dość duża powierzchnia ataku. Oczywiście, jeśli uniknąłeś również podwójnych cudzysłowów, to wracamy do punktu wyjścia. ;)
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Twoja obrona zawiedzie, jeśli:
  • żądanie oczekuje liczby, a nie ciągu
  • istniał inny sposób przedstawienia pojedynczego cytatu, w tym: [list][*]sekwencja ucieczki, taka jak \ 039
  • Znak Unicode

[/*]
[/list]
(w tym drugim przypadku powinno to być coś, co zostanie rozszerzone dopiero po dokonaniu wymiany)
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Jakim brzydkim kodem byłaby ta cała dezynfekcja danych wejściowych użytkownika! Następnie niezdarny StringBuilder dla instrukcji SQL. Przygotowana metoda instrukcji daje dużo czystszy kod, a korzyści płynące z wstrzykiwania SQL są naprawdę miłym dodatkiem.
Poza tym, po co odkrywać koło na nowo?
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Zamiast zmieniać jeden cytat na dwa (jak to wygląda), dlaczego po prostu nie zastąpić go apostrofem, cytatem lub całkowicie go usunąć?
W każdym razie to trochę Kluge ... zwłaszcza jeśli legalnie masz rzeczy (takie jak imiona), które mogą używać pojedynczych cudzysłowów ...
UWAGA: Twoja metoda zakłada również, że wszyscy pracujący nad aplikacją zawsze pamiętają o wyczyszczeniu danych wejściowych, zanim wejdą one do bazy danych, co prawdopodobnie nie jest realistyczne w większości przypadków.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Chociaż możesz znaleźć rozwiązanie, które działa dla łańcuchów, w przypadku predykatów numerycznych musisz również upewnić się, że przekazują tylko liczby (proste sprawdzenie - czy można je przeanalizować jako int/double/decimal?).
To dużo dodatkowej pracy.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Może to zadziała, ale wydaje mi się to trochę dziwne. Zalecałbym sprawdzenie poprawności każdego wiersza, porównując go z wyrażeniem regularnym.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:


Tak, możesz, jeśli ...
>
Po zbadaniu tego wątku myślę, że wejście wyczyściło się w sposób, który sugerowałeś, jest bezpieczny, ale tylko zgodnie z tymi zasadami:
  • nigdy nie pozwalasz, aby wartości łańcuchowe dostarczone przez użytkownika stały się czymś innym niż literały łańcuchowe (tj. unikaj podawania opcji konfiguracyjnej: "wprowadź tutaj dodatkowe nazwy kolumn/wyrażenia SQL:"). Typy wartości inne niż łańcuchy (liczby, daty, ...) :) konwertują je na własne typy danych i zapewniają procedurę dla literału SQL z każdego typu danych. [list][*]Sprawdzanie instrukcji SQL jest problematyczne

[/*]
[*]
albo używasz kolumn
nvarchar
/
nchar
(i prefiksów literałów ciągu
N
) LUB wartości granicznych zawartych w
varchar <!-- code kolumny-->/[code]char
, tylko do znaków ASCII (np. rzut wyjątek podczas tworzenia instrukcji SQL) [/code]
  • w ten sposób unikniesz automatycznej konwersji apostrofu z CHAR (700) na CHAR (39) (i być może innych podobnych hacków Unicode)

[/*]
[*]
zawsze sprawdzasz długość wartości, aby pasowała do rzeczywistej długości kolumny (wyjątek rzutowania, jeśli jest większa)
  • wystąpił znany błąd w SQL Server dotyczący obejścia błędu SQL wyrzuconego podczas obcięcia (prowadzącego do cichego obcięcia)

[/*]
[*]
gwarantujesz, że
SET QUOTED_IDENTIFIER
jest zawsze
ON
  • uważaj, działa to podczas parsowania, czyli nawet w niedostępnych sekcjach kodu

[/*]
[/list]
Przestrzegając tych 4 punktów, musisz być bezpieczny. Jeśli złamiesz którykolwiek z nich, otworzy się ścieżka do wstrzyknięcia SQL.

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się