Bezpieczeństwo aplikacji

Transkrypt

Bezpieczeństwo aplikacji
Bazy danych
Bezpieczeństwo aplikacji
237
238
Bazy danych
Przegląd zagadnień
Najczestsze bledy programistów
SQL Injection
Podsumowanie
Laboratorium
Nawet najlepiej zabezpieczona baza danych moŜe paść ofiarą ataku
przeprowadzonego z poziomu aplikacji, która z bazy danych korzysta. Dlatego
waŜne jest, by administratorzy i programiści byli świadomy zagroŜeń, jakie
niesie za sobą dostęp do baz danych przy pomocy zewnętrznych aplikacji.
Prawdopodobnie najwięcej przypadków nieautoryzowanego dostępu do danych
wynika z błędów programistycznych. Dlatego niezbędne jest stałe edukowanie
programistów w temacie bezpieczeństwa dostępu do danych.
Bazy danych
239
Najczęstsze błędy programistów
Programowanie z dostepem do danych - bledy
Programowanie z dostepem do danych - najlepsze
nawyki
Wyobraź sobie, Ŝe jesteś programistą. Praktycznie kaŜda dzisiejsza
aplikacja korzysta z bazy danych. Bazy danych słuŜą jako magazyny danych,
jako przechowalnia danych uwierzytelniających uŜytkowników w aplikacji,
jako podstawa pod wiele mechanizmów (cache'owanie, profile, raporty).
Zrozumienie zasad pisania bezpiecznych z punktu widzenia dostępu do danych
aplikacji jest kluczem do tworzenia dobrych programów.
240
Bazy danych
Programowanie z dostępem do danych - błędy
Najczęściej popełniane przez programistów błędy to:
•
•
•
•
•
•
dostęp do serwera baz danych z uŜyciem konta o zbyt duŜych
uprawnieniach - powoduje to, Ŝe w przypadku ataku potencjalny
agresor działa w SZBD często z uprawnieniami administratora,
przechowywanie kluczowych danych, takich jak hasła, w plikach
konfiguracyjnych aplikacji - zdobycie takich danych często otwiera
drogę potencjalnemu agresorowi,
brak kontroli nad danymi wprowadzanymi w aplikacji przez
uŜytkowników - daje to bardzo często moŜliwość ataku SQL Injection,
następstwem czego moŜe być nieuprawniony dostęp do danych,
a w skrajnych przypadkach nawet przejęcie kontroli nad bazą danych
lub serwerem,
wyświetlanie w aplikacji domyślnych komunikatów błędów SZBD powoduje to często ujawnienie struktury bazy danych i uŜytych
w aplikacji zapytań SQL, co prowadzi na ogół do ataku typu SQL
Injection,
błędne podejście przy wykrywaniu nieprawidłowości w danych
wprowadzanych przez uŜytkownika - często programista stara się
wypisać wszystkie przypadki, które są według niego nieprawidłowe,
pominięcie jednego z przypadków tworzy lukę w bezpieczeństwie,
brak kontroli nad zasobami serwera baz danych - pozostawianie
otwartych połączeń, nie zamykanie obiektów (jak na przykład
kursory).
Programowanie z dostępem do danych - najlepsze nawyki
Jak zatem naleŜy pisać aplikacje? NaleŜy trzymać się pewnych zasad.
•
•
•
•
•
•
•
•
•
•
UŜywaj konta o minimalnych uprawnieniach niezbędnych do
wykonania operacji w bazie danych.
Nigdy nie ufaj uŜytkownikom aplikacji. Kontroluj wprowadzane przez
nich dane.
Sprawdzaj tylko, czy wprowadzane przez uŜytkowników dane są tym,
czego się spodziewasz, a resztę odrzucaj.
Nie wyświetlaj domyślnych komunikatów o błędach w aplikacji
(zwłaszcza w aplikacjach WWW).
Jeśli uŜywasz transakcji, staraj się, by były one jak najkrótsze.
Nigdy nie trzymaj danych poufnych w plikach konfiguracyjnych,
chyba Ŝe w postaci zaszyfrowanej.
Zawsze sprzątaj po sobie - zamykaj otwarte przez aplikację połączenia
z serwerami.
W razie potrzeby zapewniaj bezpieczne przesyłanie danych po sieci
(uŜywaj SSL).
UŜywaj procedur składowanych i widoków do implementacji
bezpiecznego dostępu do danych.
Staraj się nie uŜywać mechanizmów powszechnie uwaŜanych za
niebezpieczne (np. dynamiczny SQL).
Bazy danych
241
SQL Injection
SQL Injection – co to takiego
Nastepstwa
Przyklady
Obrona
SQL Injection to dziś wśród programistów i administratorów baz
danych prawie legenda. Mimo to wciąŜ zdarzają się sytuacje, w których
aplikacja jest napisana tak, Ŝe umoŜliwia ten atak.
242
Bazy danych
SQL Injection - co to takiego?
SQL Injection to atak na bazę danych przeprowadzony przy uŜyciu
nieprawidłowo napisanej aplikacji. W ataku tym agresor wykorzystuje fakt, Ŝe
aplikacja nie sprawdza lub sprawdza niedostatecznie dane wprowadzane w
aplikacji przez uŜytkowników. Dzięki temu atakujący jest w stanie podać
fragment kodu języka SQL, który wykona w bazie danych czynność
niedozwoloną i nieprzewidzianą z punktu widzenia programisty.
Co jest najwaŜniejsze, na atak ten jest naraŜony kaŜdy SZBD, jeśli tylko istnieje
odpowiednio źle napisana aplikacja, która się do tego systemu dostaje
i korzysta z baz w nim przechowywanych.
SQL Injection – następstwa
Następstwa ataku SQL Injection mogą być róŜne. Najczęściej
występujące objawy to:
•
•
•
•
•
nieuprawniony dostęp do danych,
udana próba uwierzytelnienia w aplikacji bez znajomości danych
uwierzytelniających,
wykonanie nieporządanej operacji w bazie danych (np. usunięcie
tabeli),
wykonanie nieporządanej operacji w SZBD (np. stworzenie nowej
bazy danych),
wykonanie nieporządanej operacji w systemie operacyjnym (skrajny
przypadek, ale moŜliwy).
SQL Injection - przykłady
Przykład 1 - Nieuprawniony dostęp do danych
-- zapytanie bez danych uŜytkownika
SELECT * FROM Uzytkownicy WHERE Login = '' AND
Haslo = ''
-- zapytanie z danymi uŜytkownika
SELECT * FROM Uzytkownicy WHERE Login = 'Pawel'
AND Haslo = 'P@ssw0rd'
-- atak SQL Injection - próba logowania
SELECT * FROM Uzytkownicy WHERE Login = '' OR 1=1
--' AND Haslo = ''
W powyŜszym przykładzie zapytanie słuŜy do uwierzytelnienia uŜytkownika
w aplikacji. Zapytanie pobiera od uŜytkownika dwie informacje: login i hasło.
W drugim fragmencie kodu na zielono zaznaczyliśmy dane wstawione przez
uŜytkownika w pola tekstowe w aplikacji. Jeśli istnieje podany przez
uŜytkownika login i na dodatek dla podanego loginu zgodzi się równieŜ hasło,
to zapytanie zwróci jeden rekord.
Bazy danych
243
Przyjrzyj się jednak trzeciemu fragmentowi kodu SQL, w którym kolorem
czerwonym zaznaczyliśmy napis wstawiony przez atakującego w pole tekstowe
słuŜące do pobrania loginu. Zakładając, Ŝe mamy do czynienia z Microsoft sQL
Server (chodzi o symbol komentarza - dwa myślniki powodują
wykomentowanie reszty kodu SQL), atak spowoduje najprawdopodobniej
udaną próbę logowania na pierwszy dostępny login.
Dlaczego ten atak zadziałał? Przyjrzyj się, co powoduje wstawienie złośliwego
kodu. JuŜ widzisz? Najpierw zamykany jest apostrof, by zapytanie było
prawidłowym zapytaniem SQL, potem następuje stworzenie warunku, który
zawsze jest prawdziwy (dla kaŜdego rekordu), wreszcie uŜywany jest symbol
komentarza w celu zignorowania pozostałej części oryginalnego zapytania.
W sumie zapytanie wybiera z tabeli wszystkie rekordy...
Taki atak ma szansę powodzenia, jeśli aplikacja wykorzystuje konkatenację do
tworzenia składni SQL w kodzie aplikacji.
Pamiętaj, Ŝe do wykonania ataku SQL Injection czasem nie jest
potrzebne uŜycie symbolu komentarza. Zamiast tego moŜna we
wszystkie pola w aplikacji wstawić warunek zawsze spełniony i tym
sposobem atak jest moŜliwy do wykonania nawet w bazach danych,
które nie oferują symbolu komentarza (np. Microsoft Access). Np.:
SELECT * FROM Uzytkownicy WHERE Login = '' OR 'a'='a' AND
Haslo = '' OR 'a'='a'
Przykład 2 - Wykonanie niepoŜądanej operacji w bazie danych
-- zapytanie bez danych uŜytkownika
SELECT * FROM Uzytkownicy WHERE Login = '' AND
Haslo = ''
-- zapytanie z danymi uŜytkownika
SELECT * FROM Uzytkownicy WHERE Login = 'Pawel'
AND Haslo = 'P@ssw0rd'
-- atak SQL Injection - próba usunięcia tabeli
SELECT * FROM Uzytkownicy WHERE Login = ''; DROP
TABLE Uzytkownicy --' AND Haslo = ''
Tym razem celem ataku nie jest zalogowanie się do aplikacji, a popsucie bazy
danych przez usunięcie tabeli (polecenie DROP TABLE). Taki atak ma szansę
powodzenia, jeśli aplikacja wykorzystuje konkatenację do tworzenia składni
SQL w kodzie aplikacji i dodatkowo aplikacja dostaje się do bazy danych w
kontekście konta o zbyt wysokich uprawnieniach (umoŜliwiających wykonanie
polecenia kasowania tabeli).
Przykład 3 - Przejęcie kontroli nad systemem operacyjnym
Czasem SZBD jest mocno zintegrowany z systemem operacyjnym. Zachodzi
wówczas moŜliwość ataku, którego efektem będzie wykonanie niepoŜądanej
operacji w samym systemie operacyjnym.
244
Bazy danych
-- zapytanie bez danych uŜytkownika
SELECT * FROM Uzytkownicy WHERE Login = '' AND
Haslo = ''
-- zapytanie z danymi uŜytkownika
SELECT * FROM Uzytkownicy WHERE Login = 'Pawel'
AND Haslo = 'P@ssw0rd'
-- atak SQL Injection - próba usunięcia tabeli
SELECT * FROM Uzytkownicy WHERE Login = '';
EXEC master..xp_cmdshell 'net user Haker P@ssw0rd
/add --' AND Haslo = ''
W powyŜszym przykładzie w trzecim bloku kodu wykonany jest atak
polegający na dodaniu uŜytkownika do systemu operacyjnego Windows.
Następnym krokiem mogłoby być dodanie uŜytkownika do grupy
administratorów
systemowych.
Taki atak ma szansę powodzenia, jeśli aplikacja wykorzystuje konkatenację do
tworzenia składni SQL w kodzie aplikacji i dodatkowo aplikacja dostaje się do
bazy danych w kontekście konta o zbyt wysokich uprawnieniach (sysadmin
w systemie Microsoft SQL Server).
SQL Injection - obrona
Aby obronić się przed SQL Injection programista powinien stosować
pewne zasady.
•
•
•
•
•
•
•
•
UŜywaj konta o minimalnych uprawnieniach niezbędnych do
wykonania operacji w bazie danych.
Nigdy nie ufaj uŜytkownikom aplikacji. Kontroluj wprowadzane przez
nich dane.
Sprawdzaj tylko, czy wprowadzane przez uŜytkowników dane są tym,
czego się spodziewasz, a resztę odrzucaj.
Nie wyświetlaj domyślnych komunikatów o błędach w aplikacji
(zwłaszcza w aplikacjach WWW).
UŜywaj procedur składowanych i ich parametrów do dostępu do
danych.
Unikaj stosowania konkatenacji (łączenia napisów) przy tworzeniu
składni SQL w kodzie aplikacji.
UŜywaj mechanizmów dostępnych w językach programowania (jak
parametry w .NET lub prepared statements w Javie).
Wykrywaj i usuwaj z podawanych przez uŜytkowników danych znaki
charakterystyczne dla języka SQL, którego uŜywa Twój SZBD.
Jako ciekawostkę podamy Ci równieŜ fakt, Ŝe wyszukiwarki
internetowe z Google na czele, zapamiętują wystąpienia komunikatów
błędów na stronach WWW. Zatem atakujący moŜe wyszukać podatne
na ataki witryny w bardzo prosty sposób, jeśli zna słowa kluczowe
komunikatów serwera (a to moŜna znaleźć chociaŜby
w dokumentacji).
Bazy danych
245
Podsumowanie
Najczestsze bledy programistów
SQL Injection
Bezpieczeństwo to temat-rzeka. Jednak znajomość podstawowych
problemów i odpowiedzi na potencjalne zagroŜenia znacznie ogranicza
moŜliwości ataku na administrowany przez Ciebie serwer. Dlatego warto
poświęcać sporo uwagi zagadnieniom bezpieczeństwa.
Bezpieczeństwo aplikacji jest równie waŜne, jak bezpieczeństwo serwera baz
danych, jako Ŝe bardzo często decyduje ono o tym, czy nasza baza będzie
funkcjonowała poprawnie i czy firma nie będzie naraŜona na straty z powodu
udanych ataków, których liczba rośnie z kaŜdym rokiem.
246
Bazy danych
Laboratorium
Bazy danych
247
SQL Injection
W tym ćwiczeniu zobaczysz składnie T-SQL symulujące cztery wersje
ataku SQL Injection.
Spreparowany przez nas złośliwy kod T-SQL wstawiany w pola
tekstowe aplikacji wyszczególniamy na czerwono.
Krok 1 - Stworzenie przykładowego mechanizmu logowania
►
►
►
►
►
►
►
Zaloguj się do maszyny wirtualnej ZBD jako uŜytkownik
Administrator z hasłem P@ssw0rd.
Kliknij Start. Z grupy programów Microsoft SQL Server 2005
uruchom SQL Server Management Studio.
W oknie logowania kliknij Connect.
Kliknij w menu głównym programu Management Studio na File.
Kliknij Open - File.
Odszukaj plik C:\Labs\Lab12\SQLInjection.sql i kliknij Open.
Zaznacz kod, który tworzy tabelę Users, w której będą przechowywane
dane umoŜliwiające uwierzytelnienie uŜytkowników, takie jak login
i hasło.
USE AdventureWorks
GO
CREATE TABLE Users
(
UserID int IDENTITY(1,1) PRIMARY KEY,
Login nvarchar(20) NOT NULL,
Password nvarchar(20) NOT NULL
)
GO
INSERT Users VALUES ('pawel','password')
INSERT Users VALUES ('tomek','password')
INSERT Users VALUES ('adam','password')
-- zapytanie uwierzytelniajace
SELECT * FROM Users WHERE Login = 'pawel' AND
Password = 'password'
►
Wciśnij F5, aby uruchomić zaznaczony fragment kodu.
Wykonanie powyŜszego fragmentu kodu powoduje utworzenie tabeli Users,
która zawiera kolumny Login (nazwa uŜytkownika) i Password (hasło).
Kolumny te przechowują dane uŜytkowników niezbędne do uwierzytelnienia.
Aby zalogować się do systemu uŜytkownik musi podać istniejący w tabeli login
i odpowiadające mu hasło.
Ostatnia linia wykonanego kodu zawiera zapytanie ilustrujące proces
logowania. Jeśli to zapytanie zwraca jakikolwiek rekord, aplikacja uznaje, Ŝe
uŜytkownik został poprawnie uwierzytelniony i jest zalogowany. Wyobraź
sobie, Ŝe dane logowania (login i hasło) uŜytkownik podaje do zapytania przy
uŜyciu aplikacji, w kodzie której zapytanie jest konstruowane przy uŜyciu
248
Bazy danych
konkatenacji (łączenia) fragmentów zapytania SELECT z zawartością pól
tekstowych zawierających wpisane przez uŜytkownika dane.
Krok 2 - Atak SQL Injection - modyfikacja pierwsza
►
Zaznacz kod, który symuluje pierwszy atak SQL Injection (patrz kod
poniŜej).
-- SQL Injection - 1
SELECT * FROM Users WHERE Login = '' OR 1=1 --'
AND Password = 'password'
►
Wciśnij F5, aby uruchomić zaznaczony fragment kodu.
Wykonanie powyŜszego fragmentu kodu spowoduje wyświetlenie całej
zawartości tabeli Users, a zarazem zalogowanie na konto pierwszego
dostępnego w tej tabeli uŜytkownika. Składnia ' OR 1=1 -- wpisana w pole
tekstowe zamiast loginu spowoduje, Ŝe zapytanie T-SQL zostanie
zmodyfikowane na zapytanie, które nie pobiera drugiego pola (hasło) na
skutek wykomentowania odpowiedniej części kodu (dwa myślniki
komentują resztę składni). Natomiast stworzony sztucznie warunek
z operatorem OR jest spełniony dla kaŜdego rekordu w tabeli (wyraŜenie
1=1 ma wartość logiczną 1).
Krok 3 - Atak SQL Injection - modyfikacja druga
►
Zaznacz kod, który symuluje drugi atak SQL Injection (patrz kod
poniŜej).
-- SQL Injection - 2
SELECT * FROM Users WHERE Login = '' OR 'a'='a'
AND Password = '' or 'a'='a'
►
Wciśnij F5, aby uruchomić zaznaczony fragment kodu.
Wykonanie powyŜszego fragmentu kodu spowoduje wyświetlenie całej
zawartości tabeli Users, a zarazem zalogowanie na konto pierwszego
dostępnego w tej tabeli uŜytkownika. RóŜnica między tą wersją ataku
a poprzednią jest taka, Ŝe tym razem nie uŜyliśmy symboli komentarza,
a jedynie wstawiliśmy w pola login i hasło odpowiednio spreparowany
fragment kodu T-SQL tworzący dwa zawsze spełnione warunki w klauzuli
WHERE (wyraŜenie 'a'='a' ma wartość logiczną 1).
Bazy danych
249
Krok 5 - Atak SQL Injection - modyfikacja trzecia
►
Zaznacz kod, który symuluje trzeci atak SQL Injection (patrz kod
poniŜej).
-- SQL Injection - 3
SELECT * FROM Users WHERE Login = ''; DROP TABLE
Users --' AND Password = 'password'
►
2. Wciśnij F5, aby uruchomić zaznaczony fragment kodu.
Wykonanie powyŜszego fragmentu kodu spowoduje próbę usunięcia tabeli
Users z bazy danych (moŜesz sprawdzić, czy tabela została usunięta
poprzez zaznaczenie i wykonanie ostatniej linii kodu z kroku 1). Operacja
ta powiedzie się, jeŜeli aplikacja, z poziomu której powyŜsze zapytanie jest
wykonywane łączy się z bazą danych w kontekście uŜytkownika, który ma
uprawnienia do usunięcia tabeli.
250
Bazy danych
Quiz - błędy programistów
W tym ćwiczeniu spróbujesz w podanym przez nas kodzie znaleźć
błędy, które sprawiają, Ŝe aplikacja staje się zagroŜeniem dla bazy danych
i serwera baz danych.
Krok 1 - Błędny kod
W poniŜszym kodzie spróbuj odnaleźć 4 błędy, które mogą mieć wpływ na
bezpieczeństwo bazy danych.
PoniŜszy kod przedstawia fragment aplikacji napisanej w języku C#.
Jeśli nigdy nie programowałeś w tym języku, nie szkodzi. Prześledź
kod, a następnie przeczytaj zapisane poniŜej pytania i odpowiedzi.
1
SqlConnection conn =
2
new
SqlConnection
("integrated
security=false;" +
"initial
catalog=AdventureWorks;data
source=ZBD;uid=sa;pwd=password");
3
SqlDataAdapter da =
4
new
SqlDataAdapter("SELECT
ProductID,
Unitprice
FROM
Production.Product
WHERE Name = '" +
txtProduct.Text + "'", conn);
5
6
try
7
{
8
da.Fill (ds);
9
dataGrid1.DataSource
=
ds.Tables[0];
10
}
11
catch (SqlException ex)
12
{
13
MessageBox.Show (ex.Message);
14
}
Krok 2 - Odnajdywanie błędów
Po prześledzeniu kodu z kroku 1 spróbuj odpowiedzieć na poniŜsze pytania
(odpowiedź moŜesz uzyskać klikając na pytaniu).
Pytanie 1.: Linia 2 kodu zawiera tzw. connection string, czyli opcje połączenia
z bazą danych. Jakie dwa błędy związane z dostępem do bazy danych znajdują
się w tych opcjach?
Odpowiedź:
A) Połączenie z serwerem nawiązywane jest za pomocą loginu ze zbyt wysokimi
uprawnieniami (sa ma najwyŜsze uprawnienia w SQL Server - naleŜy do roli
sysadmin).
B) śaden login lub konto nie powinno mieć tak prostego hasła, jakie widnieje
w linijce 2 kodu (password to jedno z pierwszych haseł na liście w atakach
słownikowych na systemy).
Bazy danych
251
Pytanie 2.: W linii 4 programista zapisał zapytanie napisane w języku T-SQL.
Jaki błąd popełnił programista w tworzeniu tego zapytania?
Odpowiedź:
Programista zbudował zapytanie uŜywając konkatenacji łańcucha
reprezentującego kod T-SQL z zawartością pola tekstowego txtProduct, co
umoŜliwia atak SQL Injection.
Większość języków programowania oferuje mechanizmy, które
pozwalają unikać podobnych konstrukcji kodu SQL. Na przykład na
platformie .NET istnieje klasa SqlParameter, która sprawia, Ŝe tekst
wpisywany w aplikacji przez uŜytkowników jest traktowany jak
zwykły tekst, a nie jak fragment kodu SQL.
Pytanie 3.: Jaki inny błąd znajdujesz w powyŜszym kodzie?
Odpowiedź:
Programista zaprogramował obsługę błędów uŜywając strukturalnego
przechwytywania wyjątków, ale wykorzystał domyślne komunikaty zwracane
przez serwer (patrz linia 13). Komunikaty te mogą zawierać informacje, których
nie powinien otrzymać uŜytkownik aplikacji. Dobrym nawykiem jest stosowanie
swoich własnych komunikatów.