(nie)błąd

Dzisiaj komentarz do tego tematu: Okradli klientów PKO BP, przez internet, bez znajomości kodów jednorazowych. Właściwie do pewnego stopnia mój komentarz jest tutaj, ale tematowi warto poświęcić kilka słów więcej.

Pierwsze podstawowe stwierdzenie: nie ma błędu w serwisie PKO - funkcja działa dokładnie tak jak powinna. Albo dokładniej – działa dokładnie tak, jak została wyspecyfikowana. Cała sytuacja natomiast jest doskonałym przykładem potwierdzającym, że mechanizm (bezpieczeństwa), które użytkownik nie rozumie, nie ma prawa działać.

Będę pisał ogólnie bez pokazywania, w których bankowościach konkretne rozwiązanie jest zastosowane. Jeśli ktoś jest ciekawy – sam może sprawdzić w banku, z którego korzysta.

O co właściwie chodzi? Chodzi o to, że ktoś uzyskał dostęp do cudzego konta w systemie (możliwość logowania), ale bez możliwości autoryzacji przelewu. Mimo tego był w stanie dokonać takich zmian, w wyniku których ofiara sama przelała na konto atakującego sporą kwotę pieniędzy.

Jak atakujący osiągnął swój cel? Jaki błąd w systemie wykorzystał? No cóż, będę uparcie twierdził, że atakujący nie wykorzystał żadnego błędu w systemie, bo takiego błędu nie było. Przy czym od razu zaznaczam, że przez błąd w systemie rozumiem sytuację, w której ktoś może wykorzystać system w sposób niezgodny z jego specyfikacją. Czyli jeśli na przykład jestem w stanie pominąć krok autoryzacji transakcji (choć jest on wymagany), jest to błąd. Jeśli jednak autoryzacja transakcji nie jest wymagana na przelew do kwoty 10 PLN, to wykorzystanie tej funkcji nie jest błędem w systemie. Nie jest błędem w systemie również wykorzystanie tej funkcji wielokrotnie przez co wyprowadzona kwota może być dużo większa niż te 10 PLN, chyba że według specyfikacji taki przelew można na przykład wykonać jedynie pewną ilość razy, a atakujący znajduje sposób na obejście tego limitu.

W tym konkretnym przypadku nieszczęsną funkcją są odbiorcy/przelewy zdefiniowane (znane również jako szablony przelewów). W przypadku większości rozwiązań są dwa typy takich szablonów:

W przypadku przelewu (szablonu) zaufanego wykonanie przelewu w oparciu o taki szablon (przelewu do takiego odbiorcy) nie wymaga dodatkowej autoryzacji. Po prostu w chwili definiowania przelewu jego (istotne) parametry są autoryzowane. Następnie każda zmiana tych istotnych parametrów wymaga autoryzacji. Użytkownik może być pewny, że operacja wykonywana z użyciem zaufanego szablonu jest dokładnie tą operacją, która została zdefiniowana (autoryzowana) przy jego tworzeniu. Każda zmiana istotnych parametrów (czyli przede wszystkim – numeru docelowego konta) wymaga ponownej autoryzacji.

Jeśli ktoś jest w stanie znaleźć możliwość modyfikacji zaufanego przelewu zdefiniowanego bez autoryzacji zmiany – jest błąd w systemie. Tak samo, jeśli ktoś może zmodyfikować parametry przelewu wykonywanego w oparciu o zaufany przelew zdefiniowany. I tak, bywają błędy w implementacji, które osiągnięcie tego celu umożliwiają.

Inaczej przedstawia się sytuacja w przypadku niezaufanego przelewu zdefiniowanego. W tym przypadku założenie jest takie, że skoro przelew tworzony w oparciu o taki szablon jest autoryzowany , to użytkownik powinien zweryfikować parametry autoryzowanej transakcji dokładnie w taki sam sposób, jak powinien to zrobić wtedy, gdy tworzy przelew “z ręki”. W takim scenariuszu sam przelew zdefiniowany nie jest “obiektem chronionym” i zmiany tego szablonu przelewu nie wymagają dodatkowej autoryzacji.

No i właśnie dochodzimy do sedna problemu – mamy dwa różne typy czegoś, co dla przeciętnego użytkownika jest po prostu “przelewem zdefiniowanym”. Dwa typy, które zachowują się w nieco odmienny sposób, w zależności od wybranych opcji (czyli od typu przelewu). I tego rozróżnienia przeciętny użytkownik nie dostrzega i nie rozumie. A skoro nie rozumie, to nie ma świadomości, że dla pewnych scenariuszy użycia powinien zachować “szczególną ostrożność”.

Niewątpliwym błędem byłaby sytuacja, w której użytkownik (atakujący) jest w stanie modyfikować parametry cudzych przelewów niezaufanych. Najczęściej ten błąd wynika z użycia identyfikatorów globalnych – atakujący manipulując identyfikatorem przelewu może zmodyfikować obiekt (przelew), który nie należy do niego. W OWASP Top10 jest to po prostu A4 – Insecure Direct Object References. Błąd trywialny (do wykorzystania i znalezienia) i powszechny – ale czasem płacą za niego 20.000$ (Szok!).

Wróćmy do naszych nieszczęsnych przelewów (szablonów) zdefiniowanych. W opisywanej sytuacji nie ma błędu technicznego, jest natomiast błąd założeń/oczekiwań(?). Przeciętny użytkownik ufa przelewowi, który sam wprowadził - zarówno w przelewie “jednorazowym”, jak i przelewie zdefiniowanym. Nie weryfikuje parametrów przelewu otrzymanych w kodzie SMS, bo przecież sam te parametry dopiero co wpisał i widzi na ekranie, że są poprawne. Albo skopiował te parametry ze strony/maila/notatki, więc na pewno są dobre. W przypadku przelewu zdefiniowanego ta wiara jest jeszcze mocniejsza – z tego szablonu korzystał wielokrotnie, nigdy nie było problemów i pieniądze trafiały do właściwego odbiorcy , dlaczego więc tym razem miałoby być inaczej?

No to kilka możliwości dlaczego miałoby być inaczej.

Przy projektowaniu mechanizmów bezpieczeństwa należy pamiętać kto z nich korzysta – człowiek. Jeśli system ma być wykorzystany masowo, a tak jest w przypadku systemów bankowości internetowej, można spodziewać się, że świadomość przeciętnego użytkownika nie będzie zbyt wysoka. Dlatego system (i mechanizm bezpieczeństwa) powinien być prosty i zrozumiały , a ilość miejsc, w których coś może pójść nie tak – zminimalizowana. Jednym z miejsc, gdzie coś może pójść nie tak, jest każda interakcja z użytkownikiem , w trakcie której użytkownik ma podjąć decyzję. Nie da się usunąć czynnika ludzkiego, nadal niektóre decyzje muszą być podejmowane przez człowieka (użytkownika), ale warto minimalizować ten udział wszędzie tam, gdzie to jest możliwe.

Coraz mocniej jestem przekonany, że mechanizmy bezpieczeństwa powinny być testowane pod względem ich użyteczności (usability). Zresztą badań w tym zakresie jest coraz więcej. Ogólnie – to mechanizmy bezpieczeństwa powinny być dostosowane do sposobu działania człowieka. Nie można oczekiwać, że człowiek dostosuje się do mechanizmu (oczekiwań projektanta). Zawsze będzie potrzebny jakiś kompromis, ale wynikowe rozwiązanie powinno być dla użytkownika intuicyjne i zrozumiałe.

Oryginał tego wpisu dostępny jest pod adresem (nie)błąd

Autor: Paweł Goleń