Bezpieczne kwerendy bazodanowe w środowisku .NET

Tworząc każdą aplikację, należy starać się przewidzieć wszelkie zagrożenia, na jakie  może być ona podatna w środowisku produkcyjnym. W przypadku aplikacji komunikujących się z bazami danych jednym z bardzo popularnych rodzajów zagrożeń jest atak SQL Injection.

SQL Injection atak

Atak SQL Injection może zostać przeprowadzony w bardzo prosty sposób, np. z użyciem formularza znajdującego się na naszej stronie. Polega on na dopisaniu do wprowadzanych w formularzu danych wyrażenia SQL. Jeżeli baza danych nie jest zabezpieczona przed tego typu atakiem wówczas wprowadzone przez użytkownika wyrażenie SQL trafi do aplikacji i zostanie wykonane wraz z wykonaniem podstawowej kwerendy znajdującej się w aplikacji. W ten sposób atakujący może zmienić zachowanie kwerendy i poprosić bazę danych o zwrócenie np. wszystkich danych użytkowników w systemie lub spowodować zalogowanie się do aplikacji bez użycia hasła.

Przykładowy atak SQL Injection powodujący zalogowanie się bez użycia hasła może wyglądać następująco

Jeżeli w aplikacji nasz kod do zalogowania wygląda tak:

Wówczas normalnie po wpisaniu w formularzu danych np. login: Jan oraz hasło: Hasło zapytanie SQL wysyłane z aplikacji wyglądać będzie następująco:

W rezultacje kwerenda SQL jaka zostanie wykonana na bazie danych będzie miała postać:

Jak widać, zapytanie budowane jest poprzez sklejanie ze sobą fragmentów tekstu. W bardzo łatwy sposób możemy więc jako login lub hasło podać tekst zawierający znaki specjalne ‘. Spowoduje to zamknięcie tekstu, po którym możemy zacząć pisać nasze własne wyrażenie SQL.

Jeżeli podamy więc login: Jan’ OR 1=1–  oraz brak hasła, to zapytanie SQL wysyłane z aplikacji wyglądać będzie następująco:

W rezultacje kwerenda SQL jaka zostanie wykonana na bazie danych będzie miała postać:

W ten prosty sposób wstrzyknięte zostało wyrażenie OR, które zawsze jest prawdziwe (oraz komentarz blokujący dalszą treść zapytania), co spowoduje zwrócenie przez bazę danych pozytywnej odpowiedzi, tak jakbyśmy pomyślnie się zalogowali.

Ataki typu SQL injection są stosunkowo proste do wykonania, a potrafią wyrządzić spore szkody. Nie wolno więc ich lekceważyć.

Ochrona przed tego typu atakami jest jednak również bardzo prosta. Przede wszytkim należy pilnować podstawowej zasady: nie wolno ufać użytkownikowi i zawsze należy sprawdzać parametry wejściowe.

Parametry wejściowe można oczywiście sprawdzać ręcznie, jednak jest to pracochłonne zajęcie, a dodatkowo można popełnić przy tym błąd.

W środowisku .NET istnieje więc kilka gotowych rozwiązań, które pozwalają w wygodny, a jednocześnie bezpieczny sposób wykonywać zapytania bazodanowe.

1. Przekazywanie parametrów poprzez SqlParameter   

Zamiast budować zapytania ręcznie można skorzystać z SqlCommand. Wówczas stały tekst kwerendy przekazujemy jako CommandText. Wszelkie parametry umieszczamy w treści z oznaczeniem @. Następnie wartości poszczególnych parametrów można przekazać dynamicznie korzystając z metody Parameters Add.
 

2. Używanie EntityFramework (lub innych frameworków pod warunkiem, że są one zabezpieczone przed atakami SQL injection)

EntityFramework jest jednym z najbardziej popularnych frameworków bazodanowych w środowisku .NET. Pozwala on budować zapytania do bazy danych za pomocą kodu C# i LINQ. Następnie kod przekształcany jest przez sam framework w zapytanie bazodanowe.

EntityFramework posiada wbudowane zabezpieczenie przed atakami SQL injection dlatego można swobodnie budować zapytania i nie ma potrzeby dodatkowego walidowania parametrów, ani nawet specjalnego przekazywania parametrów (tak jak ma to miejsce przy korzystaniu z SqlCommand).

Nasze zapytanie mogłoby więc wyglądać tak: