Zdaję sobie sprawę, że sparametryzowane zapytania SQL są optymalnym sposobem oczyszczenia 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, "'", "''") & "'"
Wszelkie pojedyncze cudzysłowy, które wprowadzi użytkownik, są zastępowane podwójnymi pojedynczymi cudzysłowami, co eliminuje możliwość zakończenia ciągu przez użytkownika, więc wszystko inne, co mogą wpisać, takie jak średniki, znaki procentu itp., Będzie częścią ciągu i faktycznie nie wykonywane jako część polecenia.
Używamy Microsoft SQL Server 2000, w przypadku którego uważam, że pojedynczy cudzysłów jest jedynym ogranicznikiem ciągu i jedynym sposobem na uniknięcie tego separatora, więc nie ma możliwości wykonania czegokolwiek wpisanego przez użytkownika.
Nie widzę żadnego sposobu na przeprowadzenie ataku SQL injection przeciwko temu, ale zdaję sobie sprawę, że gdyby było to tak kuloodporne, jak mi się wydaje, ktoś inny by już 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 kodu SQL przeszedł przez tę technikę oczyszczania? Przykładowe dane wejściowe użytkownika wykorzystujące tę technikę byłyby bardzo pomocne.
AKTUALIZACJA:
Nadal nie znam żadnego sposobu na skuteczne przeprowadzenie ataku SQL injection na ten kod. Kilka osób zasugerowało, że ukośnik odwrotny pomija jeden pojedynczy cudzysłów, a drugi kończy ciąg, tak aby reszta ciągu została wykonana jako część polecenia SQL, i zdaję sobie sprawę, że ta metoda zadziała, aby wstrzyknąć SQL do baza danych MySQL, ale w SQL Server 2000 jedynym sposobem (jaki udało mi się znaleźć) na uniknięcie pojedynczego cudzysłowu jest użycie innego pojedynczego cudzysłowu; ukośniki odwrotne tego nie zrobią.
I chyba że istnieje sposób na zatrzymanie zmiany znaczenia pojedynczego cudzysłowu, żadna z pozostałych danych wejściowych użytkownika nie zostanie wykonana, ponieważ całość zostanie potraktowana jako jeden ciągły ciąg.
Rozumiem, że istnieją lepsze sposoby odkażania danych wejściowych, ale naprawdę jestem bardziej zainteresowany dowiedzeniem się, dlaczego metoda, którą podałem powyżej, nie działa. Jeśli ktoś zna jakiś konkretny sposób przeprowadzenia ataku typu SQL injection przeciwko tej metodzie dezynfekcji, bardzo chciałbym to zobaczyć.
Odpowiedzi:
Przede wszystkim to po prostu zła praktyka. Sprawdzanie poprawności danych wejściowych jest zawsze konieczne, ale jest też zawsze niepewne.
Co gorsza, sprawdzanie poprawności czarnej listy zawsze jest problematyczne, znacznie lepiej jest wyraźnie i ściśle określić, jakie wartości / formaty akceptujesz. Wprawdzie nie zawsze jest to możliwe - ale do pewnego stopnia zawsze trzeba to robić.
Niektóre artykuły naukowe na ten temat:
Chodzi o to, że każdą utworzoną przez Ciebie czarną listę (i zbyt liberalne białe listy) można ominąć. Ostatni link do mojej pracy pokazuje sytuacje, w których można ominąć 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 trywialnie mała, będziesz musiał zajmować się konserwacją, a może pewną ilością zarządzania: jak zapewnić, że jest wykonywana dobrze, wszędzie przez cały czas?
Jak to zrobić:
źródło
sp_executesql
zamiastEXEC
). Oznacza to, że można dynamicznie generować instrukcję SQL, o ile żaden z połączonych tekstów nie pochodzi od użytkownika. Ma to również zalety w zakresie wydajności;sp_executesql
obsługuje buforowanie.OK, ta odpowiedź będzie dotyczyła aktualizacji pytania:
Teraz, oprócz odwrotnego ukośnika MySQL - i biorąc pod uwagę, że tak naprawdę mówimy o MSSQL, są właściwie 3 możliwe sposoby, aby nadal wstrzykiwać kod SQL przez SQL
Weź pod uwagę, że nie wszystkie one będą ważne przez cały czas i są bardzo zależne od twojego obecnego kodu:
Wtedy to, co otrzymujesz - to nazwa użytkownika, ucieczka, a następnie skrócenie do 20 znaków. Problem tutaj - wstawię swój cytat do 20. znaku (np. Po 19 a), a Twój uciekający cytat zostanie obcięty (w 21. znaku). Następnie SQL
w połączeniu z wyżej wymienioną źle sformułowaną nazwą użytkownika spowoduje, że hasło będzie już poza cudzysłowami i będzie zawierało bezpośrednio ładunek.
3. Przemyt Unicode - w pewnych sytuacjach możliwe jest przekazanie wysokiego poziomu znaku Unicode, który wygląda jak cudzysłów, ale nie jest - dopóki nie dotrze do bazy danych, gdzie nagle się znajduje . Ponieważ nie jest to cytat, kiedy go zatwierdzisz, przejdzie przez proste ... Zobacz moją poprzednią odpowiedź, aby uzyskać więcej informacji i link do oryginalnych badań.
źródło
W skrócie: nigdy nie uciekaj przed zapytaniami. Z pewnością coś pójdzie nie tak. 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, żeby robić to samemu.
źródło
Zdaję sobie sprawę, że minęło dużo czasu po zadaniu pytania, ale ...
Jednym ze sposobów przeprowadzenia ataku na procedurę „cytowania argumentu” jest obcięcie łańcucha. Według MSDN w SQL Server 2000 SP4 (i SQL Server 2005 SP1) zbyt długi ciąg zostanie po cichu obcięty.
Kiedy cytujesz łańcuch, zwiększa się jego rozmiar. Każdy apostrof się powtarza. Można to następnie wykorzystać do wypchnięcia części kodu SQL poza bufor. Możesz więc skutecznie odciąć części klauzuli where.
Byłoby to prawdopodobnie najbardziej przydatne w scenariuszu ze stroną „administratora użytkownika”, w którym można by nadużywać instrukcji „aktualizacja”, aby nie wykonywać wszystkich sprawdzeń, które powinien wykonać.
Więc jeśli zdecydujesz się zacytować wszystkie argumenty, upewnij się, że wiesz, co się dzieje z rozmiarami ciągów i dopilnuj, aby nie doszło do obcięcia.
Poleciłbym iść z parametrami. Zawsze. Żałuję tylko, że nie mogę wymusić tego w bazie danych. Efektem ubocznym jest większe prawdopodobieństwo uzyskania lepszych trafień w pamięci podręcznej, ponieważ więcej instrukcji wygląda tak samo. (Z pewnością było to prawdą w przypadku Oracle 8)
źródło
Użyłem tej techniki podczas korzystania z funkcji „wyszukiwania zaawansowanego”, gdzie jedyną realną odpowiedzią było zbudowanie zapytania od podstaw. (Przykład: pozwól użytkownikowi wyszukiwać produkty w oparciu o nieograniczony zestaw ograniczeń dotyczących 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. Jak zauważył inny odpowiadający, może jednak zajść potrzeba zajęcia się ucieczką wsteczną (choć nie podczas przekazywania zapytania do SQL Server za pomocą ADO lub ADO.NET, przynajmniej - nie może ręczyć za wszystkie bazy danych lub technologie).
Problem polega na tym, że naprawdę musisz być pewien, 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 podane przez użytkownika? Jeśli tak, trzeba im też uciec. Moja odpowiedź brzmi: staram się przeprowadzić dezynfekcję tak późno, jak to możliwe (ale nie później!) Podczas konstruowania zapytania SQL.
Jednak w większości przypadków wiązanie parametrów jest drogą do zrobienia - jest po prostu prostsze.
źródło
Warunki sanitarne wejściowe nie są czymś, co chcesz być pół-dupkiem. Użyj całego swojego tyłka. Używaj wyrażeń regularnych w polach tekstowych. TryCast swoje liczby na odpowiedni typ liczbowy i zgłoś błąd walidacji, 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 od użytkownika są wrogie.
źródło
flavors
tej stronie).Jak się wydaje, to i tak zły pomysł.
A co z czymś takim jak ucieczka przed cudzysłowem w ciągu: \ '
Twoja zamiana spowodowałaby: \ ''
Jeśli ukośnik odwrotny zmienia znaczenie pierwszego cudzysłowu, to drugi cudzysłów kończy ciąg.
źródło
Prosta odpowiedź: czasami zadziała, ale nie zawsze. Chcesz używać sprawdzania poprawności białej listy we wszystkim, co robisz, 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 procesów we wszystkim , ale po raz kolejny nie zawsze jest to możliwe, więc musisz użyć sp_execute z parametrami.
Istnieją sposoby na obejście wszelkich użytecznych czarnych list, które możesz wymyślić (a także niektórych białych list).
Przyzwoity zapis jest tutaj: http://www.owasp.org/index.php/Top_10_2007-A2
Jeśli chcesz to zrobić jako szybką naprawę, aby mieć czas na zainstalowanie prawdziwego, zrób to. Ale nie myśl, że jesteś bezpieczny.
źródło
Są na to dwa sposoby, bez wyjątków, aby uchronić się przed wstrzyknięciami SQL; przygotowane instrukcje lub sparametryzowane procedury składowane.
źródło
Jeśli masz sparametryzowane zapytania, powinieneś ich używać przez cały czas. Wystarczy, że jedno zapytanie przejdzie przez sieć i Twoja baza danych jest zagrożona.
źródło
Tak, to powinno działać, dopóki ktoś nie uruchomi SET QUOTED_IDENTIFIER OFF i nie użyje podwójnego cudzysłowu.
Edycja: nie jest to tak proste, jak uniemożliwienie złośliwemu użytkownikowi wyłączenia cytowanych identyfikatorów:
QUOTED_IDENTIFIER może się wyłączyć na wiele sposobów bez Twojej wiedzy. Trzeba przyznać - nie jest to exploit dymiący, którego szukasz, ale jest to dość duża powierzchnia ataku. Oczywiście, jeśli uniknąłeś podwójnych cudzysłowów - to wracamy do punktu wyjścia. ;)
źródło
Twoja obrona zawiodłaby, gdyby:
(w tym drugim przypadku musiałoby to być coś, co zostało rozwinięte dopiero po wykonaniu wymiany)
źródło
Patrick, czy dodajesz pojedyncze cudzysłowy wokół WSZYSTKICH danych wejściowych, nawet liczbowych? Jeśli masz dane numeryczne, ale nie otaczasz go pojedynczymi cudzysłowami, masz ekspozycję.
źródło
Cóż za brzydki kod byłoby takie oczyszczanie danych wprowadzanych przez użytkownika! Następnie niezgrabny StringBuilder dla instrukcji SQL. Przygotowana metoda instrukcji daje w efekcie znacznie czystszy kod, a zalety SQL Injection to naprawdę fajny dodatek.
Po co też odkrywać koło na nowo?
źródło
Zamiast zamieniać pojedynczy cytat na (jak wygląda) dwa pojedyncze cudzysłowy, dlaczego nie zmienić go po prostu na apostrof, cytat lub całkowicie go usunąć?
Tak czy inaczej, jest to trochę kłopotliwe ... 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 aplikacją zawsze pamiętają o wyczyszczeniu danych wejściowych, zanim trafią one do bazy danych, co prawdopodobnie nie jest realistyczne przez większość czasu.
źródło
Chociaż możesz znaleźć rozwiązanie, które działa dla łańcuchów, w przypadku predykatów liczbowych musisz również upewnić się, że przekazują one tylko liczby (proste sprawdzenie, czy można je przeanalizować jako int / double / decimal?).
To dużo dodatkowej pracy.
źródło
To może zadziałać, ale wydaje mi się to trochę dziwne. Zalecam sprawdzenie, czy każdy ciąg jest prawidłowy, testując go zamiast tego w wyrażeniu regularnym.
źródło
Tak, możesz, jeśli ...
Po przestudiowaniu tematu uważam, że wejście odkażone, jak sugerowałeś, jest bezpieczne, ale tylko na tych zasadach:
nigdy nie pozwalasz, aby wartości łańcuchowe pochodzące od użytkowników 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, ...): przekonwertuj je na ich rodzime typy danych i zapewnij procedurę dla literału SQL z każdego typu danych.
albo używasz
nvarchar
/nchar
kolumny (i prefiksujesz literały łańcuchowe zN
) LUB ograniczasz wartości wchodzące dovarchar
/char
kolumny tylko do znaków ASCII (np. rzucaj wyjątek podczas tworzenia instrukcji SQL)zawsze sprawdzasz długość wartości, aby pasowała do rzeczywistej długości kolumny (wyjątek, jeśli jest dłuższy)
upewniasz się, że tak
SET QUOTED_IDENTIFIER
jest zawszeON
Przestrzegając tych 4 punktów, powinieneś być bezpieczny. Jeśli naruszysz którekolwiek z nich, otworzy się sposób na wstrzyknięcie SQL.
źródło