Jak modelować zagrożenia za pomocą STRIDE?

Jak modelować zagrożenia za pomocą STRIDE?

Praktyka modelowania zagrożeń podczas tworzenia oprogramowania wymaga sporego przygotowania i dużej wiedzy ze strony zespołu, który ją przeprowadza. Jeżeli zespoły deweloperskie dopiero zaczynają stosować takie podejście, warto im ułatwić wejście w to zagadnienie. Temu służy właśnie STRIDE.

W tym celu przydatne jest obudowanie modelowania zagrożeń w łatwy do zrozumienia i powtarzany proces. Dzięki temu nawet osoby, które na co dzień nie zajmują się bezpieczeństwem, będą w stanie w sprawny sposób brać udział w wymyślaniu kolejnych zagrożeń.

Jako przykład załóżmy, że nasz zespół buduje klasyczny sklep internetowy. Posiada on proste funkcjonalności w stylu:

  • przeglądanie artykułów, 
  • dodawanie do koszyka, 
  • zamawianie, 
  • obsługa płatności online, 
  • wysyłka potwierdzeń mailowych. 

Widzisz pewnie, że to mocno uproszczony przykład, ale to celowe. Nie chcę tu komplikować wchodzeniem w szczegóły, a tak standardowa aplikacja w zupełności wystarczy nam, by przyjrzeć się temu, jak podejść do modelowania zagrożeń.

Całość procesu pracy nad modelowaniem zagrożeń można zamknąć w 4 punktach:

  1. Zdefiniowanie co budujemy
  2. Szukanie zagrożeń
  3. Planowanie rozwiązań
  4. Walidacja rozwiązań

Zdefiniowanie co budujemy

Pierwszym krokiem, który musimy wykonać, żeby być w stanie całościowo myśleć o zagrożeniach, jest zdefiniowanie tego, co tworzymy i jak to działa. Dopiero wtedy będziemy świadomi wszystkich elementów systemu, które mogą być podatne na różne ataki.

Większość materiałów, które znajdziemy na temat modelowania ryzyka zaleca rozpoczęcie od narysowania diagramu przepływu danych w naszym systemie. Jeżeli jesteś zainteresowany tym tematem i masz ochotę poznać ten standard to zachęcam do przeczytanie niniejszego artykułu: (artykuł niedługo dostępny).

Ja jednak nie przepadam za ścisłym trzymaniem się standardów podczas tworzenia diagramów. Moją opinię w tym temacie możesz poznać tutaj (artykuł niedługo dostępny). W związku z tym sam preferuję korzystanie z diagramów opisujących nasz system, które już mamy dostępne. Zakładając oczywiście, że zespół deweloperski takowe stworzył i co najważniejsze – aktualizuje je.

Jeżeli nie, to w tym momencie najwyższy czas, by usiąść i diagramy stworzyć. Praca ta zdecydowanie się opłaci zarówno podczas modelowania zagrożeń (do którego zaraz wreszcie dojdziemy) jak i podczas samego utrzymania aplikacji.

Tak więc zacznijmy od diagramu. Może to być diagram komponentów, diagram sekwencji, itp. To, co jest nam potrzebne i co powinniśmy umieścić na tych diagramach, to przede wszystkim informacje:

  • jakie serwisy/usługi mamy w naszej aplikacji, 
  • jak przepływają dane pomiędzy nimi, 
  • które serwisy są nasze (w naszej sieci wewnętrznej), a które są zewnętrzne, 
  • gdzie przechowujemy dane. 
STRIDE - przykład

Naszą przykładową aplikację możemy zamodelować w sposób przedstawiony powyżej. 

Mamy aplikację frontendową, która łączy się z API, a ono wykorzystuje bazę danych, usługę mailową i providera płatności. Brzmi bardzo standardowo. Dodatkowo na diagramie zaznaczone są kategorie danych wymienianych z określonymi usługami. To wystarczy do opisu, jak zbudowany jest nasz system.

Szukanie zagrożeń

Mając opis naszego systemu możemy zastanowić się, które jego elementy są podatne na różnego rodzaju zagrożenia. Z tym zadaniem pomoże nam tytułowy STRIDE.

STRIDE jest to metoda klasyfikacji zagrożeń bezpieczeństwa różnego rodzaju aplikacji, która pomaga w wyszukiwaniu zagrożeń dla poszczególnych części systemu.

STRIDE jest to tak naprawdę akronim, gdzie kolejne litery oznaczają kolejne grupy zagrożeń dla naszych aplikacji:

  • Spoofing – czy ktoś może podszyć się pod cudzą tożsamość? (np. wykraść dane dostępowe);
  • Tampering – czy ktoś może zmodyfikować dane wysyłane/odbierane przez aplikację niezgodnie ze sposobem działania aplikacji?  (np. zmienić kwotę do zapłaty przed przekierowaniem do bramki płatności);
  • Repudiation – czy ktoś może po wykonaniu szkodliwej czynności w systemie zatrzeć po sobie ślady? czy jesteśmy w stanie mu to udowodnić (np. w przypadku celowej zmiany konta w systemie);
  • Information disclosure – czy ktoś może uzyskać dostęp do wrażliwych, prywatnych danych, do których nie powinien mieć dostępu? (np. dane adresowe innych użytkowników systemu);
  • Denial of Service – czy ktoś może spowodować niedostępność lub choćby czasowe zepsucie systemu? (np. w wyniku obciążenia systemu ponad jego możliwości);
  • Elevation of Privilege – czy ktoś może uzyskać dostęp do danych lub akcji, do których nie powinien mieć dostępu? (np. przedstawiając się jako użytkownik z wyższymi uprawnieniami).
STRIDE - opis

To bardzo użyteczna kategoryzacja. Jednak jak ma się ona do naszego systemu?

Mając zbudowany model działania systemu możemy do każdego elementu, który tworzymy zadać powyższe pytania. 

Przechodząc tak przez każdy element naszej architektury, możemy w ustrukturyzowany sposób przeanalizować całość systemu. Jednak nie dla każdego elementu musimy zadawać sobie wszystkie przedstawione wyżej pytania. Niektóre grupy zagrożeń STRIDE odnoszą się tylko do wybranych elementów systemu. Podział na co należy zwrócić uwagę najlepiej pokazać w tabelce.

Element diagramu/systemuSTRIDE
Proces/wewnętrzny komponentTakTakTakTakTakTak
Zewnętrzny komponentTakTak
Przesył danychTakTakTak
Magazyn danychTakTakTakTak

Tak więc spójrzmy jeszcze raz na nasz przykład i przeanalizujmy jak można podejść do zagrożeń dla zaznaczonego na diagramie przepływu danych pomiędzy aplikacją front-endową, a API.

STRIDE - przykład

Z tabelki wynika, że interesują nas tylko ryzyka STRIDE:

Tampering – czy ktoś może zmodyfikować dane wysyłane/odbierane przez aplikację niezgodnie ze sposobem działania aplikacji?

  • ktoś może zmodyfikować cenę artykułu podczas wysyłki podsumowania danych do serwera, 
  • ktoś może umieścić wektor ataku SQL Injection w polach imię i nazwisko. 

Information disclosure – czy ktoś może uzyskać dostęp do wrażliwych, prywatnych danych, do których nie powinien mieć dostępu?

  • ktoś może zmodyfikować id w treści requestów i w ten sposób zdobyć dostęp do nie swoich danych, 
  • ktoś może wpiąć się atakiem Man in the Middle w niezabezpieczone połączenie HTTP,
  • ktoś może wysłać request zapisujący dane zasobu, do którego nie ma uprawnień.

Denial of service – czy ktoś może spowodować niedostępność lub choćby czasowe zepsucie systemu?

  • ktoś może wysłać wiele takich samych zapytań, obciążając serwer. 

Więcej o samych zagrożeniach w ramach danej grupy związanych z określonym elementem systemu w osobnym artykule (link dostępny później). 
Analizując w ten sposób aplikację mamy wiedzę o potencjalnych zagrożeniach. Powinniśmy je na bieżąco spisywać, żeby płynnie przejść do kolejnego kroku. 

Planowanie rozwiązań

W tym kroku zaczynają się schody. Jedna sprawa to znalezienie zagrożeń, a zupełnie inna to zabezpieczenie naszej aplikacji przeciwko nim. Tutaj sprawa jest skomplikowana ponieważ bardzo mocno zależy to od języka i technologii, w której tworzymy nasz system.

Jako podstawę warto wziąć pod uwagę następujące rozwiązania (najlepiej w tej kolejności):

  1. Czy możemy rozwiązać ten problem narzędziem już wykorzystywanym u nas w firmie? Być może problem ten został już rozwiązany w innych aplikacjach.
  2. Jakie rozwiązania danego problemu oferują standardy branżowe?
  • Tutaj warto spojrzeć przede wszystkim do zbioru rozwiązań bezpieczeństwa: OWASP Cheat Sheet
  1. Jak podobny problem został rozwiązany przez innych? Tu możemy szukać rozwiązań na blogach lub forach internetowych.

Jak widać mechanizm jest tu dość ogólny, ponieważ spektrum problemów bezpieczeństwa jest szerokie. A jeżeli dodamy do tego fakt, że każdy problem można rozwiązać na wiele sposobów, które zależą mocno od architektury systemu to widać, że niemożliwe jest określenie uniwersalnego rozwiązania do każdego problemu.

Walidacja rozwiązań

Na koniec, gdy już znajdziemy istotne podatności w naszym systemie oraz zaplanujemy jak je zabezpieczyć, warto poświęcić jeszcze trochę czasu na weryfikację, czy zaprojektowane mitygacje spełniają następujące warunki:

  • czy rzeczywiście rozwiązują problem?
  • czy rozwiązania te są dobrze umiejscowione w ekosystemie? np. czy powinny być uwspólnione dla wszystkich aplikacji. 

Po krótkiej praktyce zauważysz pewnie, że STRIDE w odniesieniu do pojedynczych elementów systemu nie zawsze jest w stanie znaleźć wszystkie zagrożenia. Należy również patrzeć na system całościowo. Dzięki temu będziemy w stanie wykryć, że potencjalnie mało niebezpieczny wyciek id ważnego zasobu może, w połączeniu z brakiem stosownych uprawnień, skompromitować nam potencjalnie bezpieczną akcję pobierania tych zasobów.

Podsumowanie

Przedstawione cztery kroki wydają się być bardzo pracochłonne i trudne. Jednak jest tak tylko na początku drogi. Im większe doświadczenie mamy w wymyślaniu możliwych zagrożeń, tym łatwiej nam to przychodzi.

W kolejnych artykułach pokażę jak można uprościć ten proces (link dostępny później).