Wykonałem następującą procedurę przechowywaną:
ALTER PROCEDURE usp_actorBirthdays (@nameString nvarchar(100), @actorgender nvarchar(100))
AS
SELECT ActorDOB, ActorName FROM tblActor
WHERE ActorName LIKE '%' + @nameString + '%'
AND ActorGender = @actorgender
Teraz próbowałem zrobić coś takiego. Może robię to źle, ale chcę mieć pewność, że taka procedura może zapobiec iniekcji SQL:
EXEC usp_actorBirthdays 'Tom', 'Male; DROP TABLE tblActor'
Poniższy obraz pokazuje, że powyższy kod SQL jest wykonywany w SSMS, a wyniki są wyświetlane poprawnie zamiast błędu:
Przy okazji dodałem tę część po średniku po wykonaniu zapytania. Następnie wykonałem go ponownie, ale kiedy sprawdziłem, czy tabela tblActor istnieje, czy nie, wciąż tam była. czy robię coś źle? Czy to naprawdę jest odporne na wstrzyknięcia? Myślę, że to, o co tutaj pytam, to czy taka procedura przechowywana jest bezpieczna? Dziękuję Ci.
EXEC usp_actorBirthdays 'Tom', 'Male''; DROP TABLE tblActor'
Odpowiedzi:
Ten kod działa poprawnie, ponieważ jest:
Aby SQL Injection działało, musisz zbudować ciąg zapytania (czego nie robisz) i nie tłumaczyć pojedynczych apostrofów (
'
) na escaped-apostrophes (''
) (są one zmieniane za pomocą parametrów wejściowych).W próbie przekazania „skompromitowanej” wartości
'Male; DROP TABLE tblActor'
ciąg jest po prostu zwykłym ciągiem.Teraz, jeśli robisz coś w stylu:
Następnie , który byłby podatny na SQL zastrzyku, z powodu , że zapytania nie jest prąd, wstępnie Parsed kontekście; to zapytanie jest w tej chwili tylko kolejnym ciągiem. Tak więc wartość
@InputParam
może być'2015-10-31'; SELECT * FROM PlainTextCreditCardInfo;
i może stanowić problem, ponieważ to zapytanie zostanie zrenderowane i wykonane jako:Jest to jeden (z kilku) głównych powodów, dla których warto stosować Procedury składowane: z natury bardziej bezpieczne (tak długo, jak nie obejdziesz tego bezpieczeństwa, budując zapytania, jak pokazałem powyżej, bez sprawdzania poprawności wartości użytych parametrów). Chociaż jeśli chcesz zbudować Dynamiczny SQL, preferowanym sposobem jest sparametryzowanie go również za pomocą
sp_executesql
:Stosując to podejście, ktoś próbuje przekazać w
'2015-10-31'; SELECT * FROM PlainTextCreditCardInfo;
dlaDATETIME
parametru wejściowego będzie się błąd podczas wykonywania procedury przechowywanej. Lub nawet jeśli procedura przechowywana zostanie zaakceptowana@InputParameter
jakoNVARCHAR(100)
, musiałaby zostać przekonwertowana na aDATETIME
, aby przejść do tegosp_executesql
wywołania. I nawet jeśli parametr w dynamicznym SQL jest typem ciągowym, w pierwszej kolejności w procedurze przechowywanej każdy pojedynczy apostrof automatycznie uciekłby do podwójnego apostrofu.Istnieje mniej znany rodzaj ataku, w którym atakujący próbuje wypełnić pole wejściowe apostrofami, tak że ciąg wewnątrz procedury składowanej, który zostałby użyty do skonstruowania dynamicznego SQL, ale zadeklarowany jako zbyt mały, nie zmieści się we wszystkim i wypycha końcowy apostrof i jakoś kończy z prawidłową liczbą apostrofów, aby nie było już „ucieczki” w ciągu. Nazywa się to Obcinaniem SQL i zostało wspomniane w artykule magazynu MSDN zatytułowanym „Nowe ataki obcięcia SQL i jak ich unikać” autorstwa Bala Neerumalla, ale artykuł nie jest już dostępny online. Wydanie zawierające ten artykuł - wydanie MSDN Magazine z listopada 2006 r. - jest dostępne tylko jako plik Pomocy systemu Windows (w .chmformat). Jeśli go pobierzesz, może się nie otworzyć z powodu domyślnych ustawień zabezpieczeń. Jeśli tak się stanie, kliknij prawym przyciskiem myszy plik MSDNMagazineNovember2006en-us.chm i wybierz „Właściwości”. Na jednej z tych kart będzie opcja „Ufaj temu typowi pliku” (lub coś w tym rodzaju), którą należy sprawdzić / włączyć. Kliknij przycisk „OK”, a następnie spróbuj ponownie otworzyć plik .chm .
Inną odmianą ataku Obcinanie jest założenie, że zmienna lokalna jest używana do przechowywania „bezpiecznej” wartości dostarczonej przez użytkownika, ponieważ zawierała ona podwójne cudzysłowy, aby można było je uciec, aby wypełnić zmienną lokalną i umieścić cudzysłów na końcu. Chodzi o to, że jeśli zmienna lokalna nie ma odpowiedniego rozmiaru, na końcu nie będzie wystarczającej ilości miejsca na drugi pojedynczy cytat, pozostaw zmienną kończącą się pojedynczym cytatem, który następnie łączy się z pojedynczym cytatem, który kończy wartość literału w dynamicznym SQL, zamieniając ten kończący pojedynczy cudzysłów w osadzony znak ucieczki pojedynczego cudzysłowu, a literał ciągów w dynamicznym SQL następnie kończy się kolejnym pojedynczym cudzysłowiem, który miał rozpocząć następny ciąg literału. Na przykład:
Tutaj dynamiczny SQL do wykonania to teraz:
Ten sam dynamiczny SQL w bardziej czytelnym formacie to:
Naprawienie tego jest łatwe. Po prostu wykonaj jedną z następujących czynności:
Nie używaj zmiennej lokalnej do przechowywania wartości „stałej”; wystarczy umieścić
REPLACE()
bezpośrednio w tworzeniu Dynamicznego SQL:Dynamiczny SQL nie jest już zagrożony:
Uwagi na temat powyższego przykładu Trunction:
DELETE tableName
być destrukcyjny, ale rzadziej doda użytkownika back-door lub zmieni hasło administratora.Aby uzyskać bardziej szczegółowe informacje dotyczące SQL Injection (obejmujące różne RDBMS i scenariusze), zobacz następujące informacje z Open Web Application Security Project (OWASP):
Testowanie SQL Injection
Powiązana odpowiedź dotycząca przepełnienia stosu podczas wstrzykiwania SQL i obcinania SQL:
Jak bezpieczny jest T-SQL po zamianie znaku zmiany znaczenia?
źródło
Prostą sprawą jest to, że w ogóle nie mylisz danych z poleceniami. Wartości parametrów nigdy nie są traktowane jako część polecenia i dlatego nigdy nie są wykonywane.
Napisałem o tym na blogu: http://blogs.lobsterpot.com.au/2015/02/10/sql-injection-the-golden-rule/
źródło