Pojęcie Trust Boundary (czasem też Security Boundary) jest wykorzystywane w celu określenia różnych "poziomów zaufania" w aplikacji. Jeśli coś przekracza trust boundary (w szczególności "wchodzi do środka") musi być traktowane jako niezaufane.
Trust Boundary
To oczywiście uproszczone wyjaśnienie tego pojęcia. Teraz trochę bardziej obrazowo. Wyobraźmy sobie dawne czasy, gród warowny (kasztelana Mirmiła) otoczony palisadą i fosą z wodą. Wejście do grodu możliwe jest przez most zwodzony i bramę, która oczywiście jest pilnowana by zbójnicy Krwawego Hegemona nie przedostali się do środka (pewnie coś pomieszałem, nie pamiętam ile lat temu ostatni raz miałem w rękach ten komiks). Świat można podzielić na bezpieczny lub zaufany znajdujący się wewnątrz palisady, do którego mają dostęp wyłącznie zweryfikowane przy bramie osoby, oraz świat zewnętrzny, który jest niezaufany. Palisada wraz z fosą to właśnie (w uproszczeniu) trust boundary, a ruch ludzi do wewnątrz/na zewnątrz można przyrównać do przepływu danych z/do aplikacji.
Teraz kilka dodatkowych pojęć (po angielsku):
- data flows - przepływy danych,
- data stores - "składnice" danych,
- processes - procesy,
- interactors/external entities - aktorzy,
- trust boundary,
Przy pomocy tych podstawowych elementów można zobrazować właściwie każdą aplikację, w szczególności aplikację internetową (webową). W zasadzie każdą taką aplikację na pewnym poziomie abstrakcji można przedstawić w sposób następujący:
Za jakość diagramu i użyte symbole przepraszam, próbuję się przyzwyczaić do DIA. Zresztą plastycznie uzdolniony nigdy nie byłem.
Jest to bardzo ogólny schemat dość typowej aplikacji internetowej:
- klient wysyła żądania (HTTP) do aplikacji i otrzymuje od niej odpowiedzi,
- aplikacja (proces) wysyła query do bazy i otrzymuje ich rezultaty,
- aplikacja wczytuje pliki (np. strony) z dysku,
Strzałki oznaczają data flow, warto zastanowić się, które z nich przekraczają trust boundary. Wszystko zależy od konkretnego przypadku, ale jeden podstawowy, praktycznie zawsze istniejący trust boundary jest umieszczony tak, jak zostało to przedstawione na poniższym schemacie:
Jeśli programiści aplikacji internetowych przyswoją sobie ogólne pojęcie trust boundary i zapamiętają, że jedna z takich granic zawsze znajduje się między klientem (przeglądarką) i aplikacją (serwerem), to dobrze. Jeszcze lepiej, jeśli zapamiętają, że wszystkie dane przekraczające trust boundary należy uznać za niezaufane i weryfikować ich poprawność.
Co to w praktyce oznacza? Przeglądarka wysyła do serwera request (żądanie) HTTP, jest ono generowane w wyniku akcji wykonanej przez użytkownika. Bardzo często programiści robią założenie, że jedyne akcje, jakie klient (przeglądarka) prześle do aplikacji (serwera), to te, które sami przygotowali (np. wyświetlając określony zbiór linków do artykułów, do których użytkownik ma dostęp). Założenie to jest błędne. Prawda jest taka, że to użytkownik kontroluje każdy element żądania, który przesyła przeglądarka do serwera. Jak może to zrobić? Choćby z pomocą narzędzi takich jak Fiddler, WebScarab czy Burp. I nie, nie ma tu różnicy, czy jest to zwykłe połączenie HTTP, czy szyfrowane połączenie HTTPS. W rezultacie wszystkie "mechanizmy zabezpieczeń" implementowane po stronie klienta należy uznać za nieskuteczne.
W szczególności do owych nieskutecznych mechanizmów zaliczyć można:
- walidację danych przez skrypty JavaScript,
- kontrolę dostępu do funkcji na poziomie GUI (np. "wyłączanie" przycisków),
- kontrolę dostępu do danych na poziomie GUI (wyświetlanie tylko linków do elementów, do których użytkownik ma dostęp),
- przekazywanie istotnych danych kontrolnych w polach ukrytych,
Co z innymi data flow? Czy nie powinno być więcej "granic"? To zależy od konkretnej architektury. Oczywiście można wykazać się dalece posuniętą paranoją i weryfikować strony wczytywane z dysku czy dane wczytywane z bazy, ale nie zawsze ma to sens. Albo inaczej - jeśli atakujący ma możliwość dowolnej modyfikacji plików na dysku lub danych w bazie danych, to znaczy, że coś poszło mocno nie tak... Na przykład kontroluje on już serwer, na którym znajduje się aplikacja, wówczas dodatkowa walidacja plików czy danych z bazy i tak nic nie da.
Oczywiście łatwo można wyobrazić sobie scenariusze, w których dodatkowe trust boundary powinno się pojawić. Na przykład, gdy w bazie znajdują się dane importowane z zewnętrznej, niezaufanej aplikacji...
W tym wypadku "nasza" aplikacja odczytując dane z bazy danych może natrafić na dane, których się nie spodziewa. "Ktoś" może przejąć WebService i w ten (pokrętny) sposób zaatakować aplikację. Gdzie w takim razie umieścić granice? Mogą być dwa przypadki:
W tym wypadku "kontrolujemy" proces importu, można więc wymusić walidację danych pobieranych z WebService i założyć, że do bazy trafiają wyłącznie dane prawidłowe. Jeśli jednak proces importu pozostaje "magiczny", dane w jakiś sposób pojawiają się w bazie i co do ich "jakości" nie można mieć żadnych założeń, diagram ten powinien prezentować się raczej w ten sposób:
To proste przykłady, ale mam nadzieję, że dobrze oddają ogólną ideę pojęcia trust boundary. A dlaczego o tym piszę? Czasami spotykam się z bardzo ciekawymi skutkami "przeoczenia" tej granicy. Bardziej ciekawymi niż wspominana już walidacja po stronie klienta, czy "kontrola dostępu" wymuszana wyłącznie przez GUI. Ale o tym napiszę już (być może) w przyszłości.
Obecnie w ramach przewodnika po bezpieczeństwie aplikacji internetowych udostępnione jest 18 przykładów. Przykłady dotyczą różnych aspektów bezpieczeństwa oraz testowania aplikacji internetowych, po części po to, by pokazać, że testy penetracyjne wcale ni
Przesłany: Jan 13, 08:50
Otrzymałem ostatnio zapytanie odnośnie przechowywania danych sesji po stronie klienta. Było ono związane z drugim z przygotowanych przeze mnie wyzwań. Jednym z istotnych elementów tego zadania była analiza danych przechowywanych po stronie klienta, co wyj
Przesłany: Feb 16, 17:35