Cześć!
To już piąty odcinek z serii OWASP Top 10.
Tym razem przyjrzymy się bliżej nieodpowiedniej kontroli dostępu.
Ta grupa powstała z połączenia 2 innych, względem listy z 2003 roku.
Wcześniej osobno mieliśmy do czynienia z nieodpowiednią kontrolą uprawnień użytkownika a także nieodpowiednio zabezpieczonym bezpośrednim odwołaniem do obiektów.
Teraz jest to jedna, szersza kategoria.
W tej grupie chodzi o to jak strona kontroluje dostęp do treści i funkcjonalności dostępnych dla różnych użytkowników.
Jeżeli użytkownik zmieniając wartość jakiegoś parametru (który okazuje się być identyfikatorem jakiegoś obiektu) jest w stanie go wyświetlić - a nie powinien mieć do niego dostępu - strona jest podatna.
Tym obiektem może być wiele rzeczy. Plik na dysku, ścieżka do katalogu czy też numer wpisu w bazie danych.
Aplikacja nie może wyświetlać obiektu bazując tylko na tym identyfikatorze - ponieważ może on być łatwo zmieniony.
Musi za każdym razem sprawdzać, czy pobrany na tej podstawie obiekt może być wyświetlony przez danego użytkownika.
I nie ma znaczenia czy jest to jakaś tajna albo losowa liczba.
Co bowiem w przypadku, gdy atakujący podpatrzy identyfikator znajdujący się w pasku adresu w przeglądarce i spróbuje z niego skorzystać?
Teoretycznie zna identyfikator, więc materiał powinien zostać wyświetlony.
Tylko, że nie jest zalogowany i nie posiada do niego dostępu.
Miejsc gdzie można natrafić na tą podatność jest kilka.
Pierwsze, to wszystkie kawałki kodu, w których odnosimy się do plików pobieranych z dysku.
Teraz może się to wydawać dziwne i niezrozumiałe, aby pobierać te pliki bazując na danych podanych przez użytkownika.
Ale taka jest smutna rzeczywistość.
Zazwyczaj programista zakłada jeden katalog, do którego przesyłane są wszystkie pliki od użytkownika.
Jeżeli chce on pobrać swój plik, przesyła odpowiednie żądanie podając w parametrze nazwę pliku.
Ta nazwa jest łączona z wcześniej zdefiniowaną ścieżką do katalogu i jeżeli plik istnieje - jest zwracany do użytkownika.
Jak zawsze - dane z zewnątrz należy traktować jako potencjalnie niebezpieczne.
I tak jest w tym wypadku.
W systemach operacyjnych, jeżeli używamy linii komend i chcemy przejść do katalogu wyżej w hierarchii - możemy użyć komendy cd
oraz znaków ../
.
Dzięki temu przeprowadzamy atak path traversal
.
Ten ciąg oznacza "przejdź katalogu wyżej" i może być nie tylko używany w linii komend, ale także we wszystkich funkcjach, które operują na plikach od użytkownika.
Jeżeli więc oprócz nazwy pliku, w parametrze przekazany zostanie ciąg ../
, to wtedy łącząc go z wcześniej zdefiniowanym katalogiem - nie będziemy pobierać plików właśnie z niego ale z katalogu wyżej.
A łącząc kilkanaście wywołań ../
możemy spreparować takie żądanie, które będzie w stanie wskazywać na dowolny plik na komputerze.
Takie zachowanie nie jest pożądane, chociażby z powodu istnienia plików /etc/passwd
oraz /etc/shadow
na Linuxie, w których to znajdują się informacje na temat haseł użytkowników.
Jakie zatem są metody obrony?
W większości języków programowania istnieją odpowiednie funkcje, które usuwają z parametru wszystkie odniesienia do katalogów i pozostawiają samą nazwę plików.
Niektórzy programiści próbują wymyślać koło na nowo i tworzą swoje własne rozwiązania - ale to nigdy nie kończy się dobrze.
Po przeczytaniu ostatnich kilku zdań możesz bowiem odnieść wrażenie, że wystarczy jedynie usunąć ciąg ../
z parametrów od użytkownika.
Ale to nie jest prawda.
Istnieje również ciąg ..\
, który jest rozpoznawalny w systemie Windows i działa dokładnie tak samo jak ../
pod Linuxem.
Jeśli nie uwzględnimy tego faktu - dalej będziemy podatni, ale na innym systemie operacyjnym.
Oczywiście najlepszym rozwiązaniem było by przechowywanie nazw plików w jakiegoś rodzaju bazie danych, tak aby użytkownik nigdy bezpośrednio nie kontrolował parametru przekazywanego do funkcji związanej z odczytywaniem plików.
Ale to nie zawsze jest możliwe.
Kolejnym miejscem, które może być podatne, są wszystkie zapytania do bazy danych.
I teraz możesz odnieść wrażenie, że przecież to już było w pierwszym odcinku, kiedy opowiadałem o SQL Injection.
Ale to nieprawda. Tutaj bowiem zakładamy, że zapytanie jest prawidłowo chronione przy pomocy na przykład prepared statement
.
Atakujący nie ma zatem żadnej możliwości dopisania jakiegoś dodatkowego warunku do zapytania.
Jedyne co kontroluje to jeden z parametrów - przekazywany do zapytania na podstawie którego zwracane są jakieś wyniki.
Aby uchronić się przed tym atakiem należy za każdym razem sprawdzać, czy użytkownik posiada dostęp do danego, zwróconego wyniku.
Samo posiadanie identyfikatora nie wystarczy.
Rozpatrzmy to na przykładzie.
Posiadamy sklep internetowy, gdzie po zakupie udostępniamy możliwość wyświetlenia faktury VAT, na której znajdują się dane adresowe oraz informacje na temat zakupionych produktów.
Użytkownik może skorzystać z tej opcji klikając w odpowiedni link znajdujący się w jego panelu.
W tym linku znajduje się parametr ID
- a tam liczba, jednoznacznie identyfikująca daną fakturę.
Tak się składa, że liczba ta to klucz główny kolumny ID w tabeli w bazie danych.
Liczba ta z każdym nowym rekordem się inkrementuje - to znaczy zwiększa o jeden.
Atakujący więc może podejrzeć dowolną fakturę innego użytkownika - wraz z jego danymi po prostu zwiększając lub zmniejszając numer faktury podawany w parametrze.
Jeżeli strona nie weryfikuje dodatkowo kto jest adresatem tej faktury - dochodzi do wycieku danych.
Głównym więc powodem tego rodzaju podatności jest myślenie programistów, że dane do serwera mogą zostać wysłane tylko w jeden sposób - to znaczy tylko z poziomu interfejsu graficznego.
A on to przecież jest bezpieczny - wszak tam wyświetlamy odnośniki tylko do miejsc, do których użytkownik posiada dostęp.
Tylko, że to nieprawda - każde żądanie można zmodyfikować używając chociażby narzędzia BURP - gdzie atakujący ma pełną kontrolę nad żądaniem wysyłanym do serwera.
Również nazwy katalogów i ścieżek można testować w poszukiwaniu plików ukrytych w tak zwanym głębokim ukryciu
.
Jest to praktyka ochrony danych komputerowych, polegająca na umieszczeniu ich w nieprzewidywalnej i trudnej do odgadnięcia dla przeciętnego użytkownika ścieżce dostępu.
Załóżmy zatem, że chcesz przesłać duży plik, który jest za duży na wiadomość email do swojego kontrahenta.
Generujesz więc losową i skomplikowaną nazwę a następnie umieszczasz go na swoim serwerze w katalogu tajne.
Następnie przesyłasz tak wygenerowaną ścieżkę do osoby, która ma pobrać plik.
Tylko, że zapominasz potem ten plik usunąć.
Teoretycznie nic się nie dzieje. Nikt nie jest w stanie zgadnąć 40 znakowej losowej nazwy.
Ale jak to bywa, nie zawsze wszystko działa tak jak powinno.
W pewnym momencie, na Twoim serwerze miała miejsce pewna błędna konfiguracja, która spowodowała, że wchodząc do katalogu tajne - można było zobaczyć listę wszystkich plików, które się tam znajdują.
Pech chciał, że w tym momencie Twoją stronę odwiedzał Google bot, który przeszukuje i analizuje Internet aby dodawać treści do wyszukiwarki.
Bot widząc listę plików w katalogu - zaindeksował każdy z nich - sprawiając tym samym, że treść pliku przestała być tajna i można ją było pobrać z poziomu wyszukiwarki.
Jednym z podstawowych testów, który powinniśmy przeprowadzić, jest przejście przez wszystkie opcje dostępne na naszej stronie jako administrator i zapisanie takiej sesji.
Następnie całą operację powtarzamy jeszcze raz - tym razem jako zwykły użytkownik - sprawdzając czy aby na pewno nie mamy dostępu do funkcjonalności dostępnych jedynie dla administratora.
Na samym końcu, to samo sprawdzamy również jako niezalogowany użytkownik - co pozwoli na upewnienie się, czy któraś z podstron nie jest dostępna dla niezalogowanego użytkownika.
Inną metodą sprawdzenia podatności jest użycie tak zwanego forced browsing
.
Enumerujemy tutaj po popularnych nazwach podstron - w stylu admin, bakcup, panel, administracja - sprawdzając tym samym, czy wszystkie z nich są odpowiednio zabezpieczone.
Ale strona to nie tylko tekst przetrzymywany głównie w bazach danych, ale także pliki graficzne - zazwyczaj przechowywane w różnego rodzaju CDN-ach na całym świecie.
Popularnym rozwiązaniem jest S3 - czyli usługa firmy Amazon pozwalająca na przetrzymywanie plików w tak zwanych kubełkach.
Przeszukując Internet możemy natrafić na wiele przykładów gdzie błędnie skonfigurowano właśnie tą usługę, sprawiając, że pliki tam przechowywane dostępne były dla każdego.
Bo na uprawnienia plików składają się nie tylko uprawnienia danego pliku, ale też uprawnienia katalogów.
Plik może być odpowiednio zabezpieczony ale jeżeli włączone jest listowanie katalogów - widoczne będą nazwy tych plików.
A czasami na samej tej podstawie można dowiedzieć się wielu interesujących rzeczy.
Osobną kwestią jest weryfikacja tokenów JWT - czyli nowego sposobu przetrzymywania informacji na temat sesji użytkownika.
W starym podejściu - sesja przechowywana jest na serwerze, w nowym natomiast dane te są przechowywane w pamięci przeglądarki i wysyłane do serwera z każdym żądaniem.
Serwer weryfikuje taki token - sprawdzając, czy jest on podpisany prawidłowym kluczem i jeśli tak - traktuje dane otrzymane w żądaniu jako prawidłowe.
Czy nasz serwer sprawdza te podpisane dane w odpowiedni sposób?
Czy klucz używany do ich podpisywania jest losowy?
Oprócz loginów i haseł, identyfikatorów sesji, tokenów JWT są jeszcze różnego rodzaju klucze API - które również muszą być odpowiednio zarządzane.
Na samym końcu nagłówki CORS - czyli mechanizm pozwalający na bezpieczne wykonywanie zapytań Cross-Origin z poziomu kodu JavaScript.
Standardowo bowiem, jeżeli z poziomu kodu JS chcemy pobrać dane z innej niż nasza bieżąca domena - taka operacja się nie powiedzie.
Jest to podyktowane względami bezpieczeństwa i tym w jaki sposób działają obecnie przeglądarki.
Podczas wysyłania żądania bowiem przeglądarka automatycznie dołącza ciasteczka użytkownika, co sprawia że serwer jest w stanie rozpoznać kto wysłał dane żądanie.
A przecież żądanie do obcej domeny może być wysłane z dowolnej strony przy użyciu kawałka JavaScriptu.
Gdyby zatem kod z obcej strony mógł wysłać żądanie do naszego serwera (a przeglądarka w tle dołączyłaby ciasteczko bieżącego użytkownika) mógłby w ten sposób uzyskać dostęp na przykład do tokenu API danego użytkownika.
A wykorzystując taki token - można wykonywać wiele akcji jako dana osoba.
Stąd też - aby zewnętrzne witryny mogły łączyć się z naszymi interfejsami API - konieczne są specjalne nagłówki.
Dzięki nim dostęp do API możliwy jest tylko dla zaufanych domen.
Błędne ich skonfigurowanie może zatem prowadzić do niebezpiecznych sytuacji.
I to już wszystko w tym odcinku.
Serdecznie zapraszam Cię do kolejnego, w którym opowiem o niepoprawnych ustawieniach w różnych frameworkach, serwerach i aplikacjach.
Free Broll provided by videezy.com
Stock footage provided by Videvo, downloaded from https://www.videvo.net
Icon made by Freepik www.flaticon.com
Design vector created by freepik - www.freepik.com