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.