O testowaniu kontroli dostępu (do funkcji)
Weryfikacja poprawności kontroli dostępu do danych oraz do funkcji jest jednym z bardziej istotnych elementów testów bezpieczeństwa aplikacji. Tematowi temu były poświęcone między innymi dwa przykłady w przewodniku po bezpieczeństwie aplikacji internetowych (Lekcja 2: Nieprawidłowa kontrola dostępu do danych oraz Lekcja 3: Nieprawidłowa kontrola dostępu do funkcji). Dziś spojrzenie na temat z nieco innej strony.
Przygotowanie do testów
W celu przetestowania kontroli dostępu do danych i funkcji dobrze jest najpierw ustalić jak ta kontrola dostępu powinna działać. W niektórych przypadkach reguły przyznawania/odmawiania dostępu są tak skomplikowane, że zrozumienie ich jest sporym wyzwaniem. Warto jednak skupić się na dość prostym przypadku, który chciałem już pokazać w drugim z dostępnych wyzwań.
W przykładzie tym w aplikacji założone są konta należące do trzech rożnych grup/roli. W zależności od roli, do której należy użytkownik, uzyskuje on dostęp do różnych funkcji. Jednym z elementów wyzwania było znalezienie błędu w kontroli dostępu, ale aspekt ten nie spotkał się z większym zainteresowaniem. Warto jednak poświęcić mu nieco uwagi, ponieważ jest to dobry przykład jak testować kontrolę dostępu, oraz jak przygotować środowisko do testów.
Ponieważ aplikacja zakłada istnienie trzech ról, czyli:
- gość,
- użytkownik,
- administrator.
Należy przygotować po jednym koncie należącym do każdej z tych grup. W tym przypadku konta takie istnieją w aplikacji, dane uwierzytelniające użytkowników należących do poszczególnych grup znajdują się w drugiej części wyjaśnienia do zadania.
Czy tego typu przygotowanie jest niezbędne? Tak i nie. Nie, bo można oprzeć się na zgadywaniu. Można wyjść z założenia, że atakujący/intruz też będzie zgadywał i być może nie zgadnie. Moim zdaniem kontrola dostępu nie polega na tym, by udziwnić nazwę funkcji tak, by atakujący jej nie znalazł, ale na tym, by aplikacja zweryfikowała, czy dany użytkownik ma prawo do wywołania określonej funkcji. By wiedzieć jak wywołanie danej funkcji powinno wyglądać, dobrze jest posiadać użytkowników z różnymi grupami uprawnień (najlepiej jeśli są to typowe role wykorzystywane w aplikacji). Dlatego uważam, że takie przygotowanie jednak jest potrzebne.
Kto co może
Kolejnym etapem powinno być ustalenie jakie funkcje dostępne są w aplikacji i ustalenie do których z nich dostęp posiadają poszczególne grupy. W przypadku wykorzystywanej jako przykład aplikacji dostępne są następujące funkcje:
- Dane użytkownika (A, U, G),
- Przeglądanie danych (A, U),
- Administracja (A),
- Wyloguj (A, U, G).
W nawiasach oznaczone zostały grupy, które mają dostęp do poszczególnych funkcji. W tym przypadku grupy reprezentowane przez użytkowników A dmin, U ser oraz G uest.
Lista przypadków testowych
Następnym krokiem jest stworzenie listy przypadków testowych, w których aplikacja powinna odmówić dostępu do danej funkcji. W tym przykładzie są dwie takie funkcje:
- Przeglądanie danych,
- Administracja,
Lista przypadków testowych wyglądać może mniej więcej tak:
- próba wywołania Administracja przez guest ,
- próba wywołania Administracja przez user ,
- próba wywołania Przeglądanie danych przez guest ,
Można się zastanawiać czy dwa pierwsze przypadki nie powinny zostać zredukowane do jednego. Teoretycznie założenie, że jeśli aplikacja prawidłowo sprawdza dostęp dla user powinna również prawidłowo sprawdzić i przypadek dla guest. Niestety, to jak działają aplikacje nie zawsze kieruje się logiką i zdrowym rozsądkiem. Dlatego zanim takie przypadki można zacząć redukować warto kilka losowo wybranych przypadków tego typu sprawdzić czy aby na pewno nasze założenia co do spójności działania mechanizmów bezpieczeństwa są uzasadnione.
Test empiryczny
Skoro wiadomo już co trzeba sprawdzić i przynajmniej mniej więcej wiadomo jak należy to zrobić, pozostaje przeprowadzenie eksperymentu, czyli wykonanie testu. Dowód pozostawiam czytelnikowi, jest trywialny (hint: AGH, algebra, jedno z najbardziej irytujących stwierdzeń w “niebieskiej(?) książce”, przynajmniej za moich czasów) :)
I to wszystko?
W zasadzie tak, przynajmniej jeśli chodzi o ogólną zasadę postępowania. Oczywiście im głębiej w las, tym więcej drzew, ale o tym może już przy innej okazji. Może w końcu zbiorę się w sobie i przygotuję kolejny odcinek bootcamp.
Tu przy okazji można wspomnieć o zapomnianym już chyba projekcie: OWASP Access Control Rules Tester Project. Przyznam, że chciałem kiedyś korzystać z tego narzędzia z czystej ciekawości, ale cierpliwości mi nie starczyło. Jeśli uwzględnić czas, który należy poświęcić na przygotowanie narzędzia do testów, okazuje się, że zrobienie testów kontroli dostępu ręcznie jest jednak szybsze. Jest to przypadek nieco zbliżony do fuzzerów – są przydatne, ale stosowanie typowych fuzzerów w trakcie typowego testu jest umiarkowanie efektywne (patrz: Po spotkaniu OWASP – fuzzery).
Oryginał tego wpisu dostępny jest pod adresem O testowaniu kontroli dostępu (do funkcji)
Autor: Paweł Goleń