Urządzenia mobilne zyskują coraz większą popularność zarówno wśród użytkowników, jak i autorów aplikacji, także tych "finansowych". Coraz więcej banków ma w swojej ofercie aplikacje dla urządzeń mobilnych, za pomocą których klienci mogą korzystać z usług swojego banku. Nie mam tu na myśli specjalnych wersji "normalnego" systemu bankowości internetowej w wersji przeznaczonej dla urządzeń mobilnych (w domyśle - inny layout, pewne ograniczenia funkcjonalne, itp.), ale specjalnie przygotowane aplikacje, które są przede wszystkim wygodniejsze dla klienta w użytkowaniu. Często aplikacje takie realizują wyłącznie GUI, cała istotna logika znajduje się po stronie banku, który udostępnia odpowiednie usługi (web service). Problem pojawia się, gdy taka aplikacja zechce przechowywać pewne dane lokalnie, na urządzeniu. Czy jest w stanie przechowywać je bezpiecznie?
Zaszyfrować - jak to łatwo powiedzieć
Bezpiecznie, czyli jak?
Właściwie co to znaczy "przechowywać bezpiecznie"? Jakie są zagrożenia? Jak wygląda threat model nawet nie tyle dla samych aplikacji mobilnych, co dla urządzeń mobilnych? Do tego tematu być może w przyszłości wrócę, tym razem ograniczę się do jednego konkretnego scenariusza: załóżmy, że atakujący ma nieograniczony dostęp do urządzenia i danych na nim przechowywanych.
W świecie idealnie kulistych kurczaków (teoria) wszystko jest proste...
Jak aplikacja może chronić swoje dane w takim scenariuszu? Odpowiedź wydaje się oczywista - dane te powinny zostać zaszyfrowane. Problem w tym, że łatwiej jest to powiedzieć, niż zrobić. To znaczy samo szyfrowanie jest proste. Jeśli wzięlibyśmy pod rozwagę Android, to aplikacje w nim działające napisane są w języku Java, a tam wystarczy zajrzeć do pakietów javax.crypto oraz java.security by znaleźć wszystko co potrzeba, by dane porządnie zaszyfrować. Jest tylko jeden mały, ale przy okazji kluczowy problem - klucze.
...ale ta wredna praktyka wszystko psuje!
No właśnie, nie chodzi przecież tylko o to, by dane rozszyfrować. Aby cała zabawa miała sens, musi istnieć możliwość ich późniejszego odszyfrowania. A to oznacza, że aplikacja musi dysponować kluczem użytym do szyfrowania danych lub być w stanie ten klucz wygenerować. Przechowywanie klucza na urządzeniu nie jest pomysłem dobrym - przypominam, że atakujący dysponuje pełnym dostępem do urządzenia i danych na nim przechowywanych. Skoro tak, będzie w stanie odzyskać klucz, a następnie dane odszyfrować. Przechowywanie klucza w postaci zaszyfrowanej problemu oczywiście nie rozwiązuje, bo w jakiś sposób trzeba przechowywać/generować klucz wykorzystany do szyfrowania klucza. Pozostaje więc chyba tylko generowanie kluczy kryptograficznych w trakcie działania aplikacji. Tylko na jakiej podstawie?
Szczerze mówiąc autorzy aplikacji mają niewielki wybór - klucz będzie generowany na podstawie danych pochodzących od użytkownika. Tylko jak wiele tych danych użytkownik będzie w stanie dostarczyć? Interfejs urządzeń mobilnych nie nadaje się do tego, by w wygodny sposób użytkownik mógł wprowadzić długie i złożone hasło. Może być (i bywa) tak, że klucz jest generowany na podstawie kodu PIN o długości np. 6 cyfr. W efekcie szyfrowanie jest iluzoryczne...
PIN o długości 6 cyfr musi być jednoznacznie przeprowadzany w klucz po to, by raz zaszyfrowane dane udało się odszyfrować. 6 cyfr to tylko 1 000 000 kombinacji. Daje to jakieś 20 bitów entropii, co jest śmieszną wartością przy kluczach o długości 128 lub 256 bitów. Sprawdzenie wszystkich możliwych kluczy w takim wypadku nie jest żadnym problemem.
Czy aplikacja może się bronić przed atakiem atakiem brute force? Teoretycznie tak, może przecież po kilku nieudanych próbach podania PIN usunąć wszystkie dane. Tylko, że szanujący się atakujący nie będzie próbował tych pinów wpisywać ręcznie. I nie będzie ich sprawdzał za pośrednictwem aplikacji. Dokładnie z tego samego powodu nie ma sensu wbudowywać w narzędzia typu KeePass opcji "samozniszczenia" bazy po wielokrotnym podaniu złego hasła. Atakujący albo nie będzie korzystał z KeePass, albo po prostu oryginalną bazę najpierw skopiuje, a później będzie atakował jej kopie.
A może by tak TPM?
Rozwiązanie problemu, o którym piszę, teoretycznie mogłoby być proste. Wystarczy jeśli w urządzeniu pojawiłby się moduł TPM i aplikacje uzyskały odpowiednie API do dostępu do niego. W tym wypadku aplikacja mogłaby generować porządny klucz i wykorzystywać go w operacji szyfrowania. Sam klucz mógłby być przechowywany w postaci szyfrowanej, a jego odszyfrowanie przy uruchamianiu aplikacji odbywałoby się z wykorzystaniem modułu TPM, który przed atakiem brute force już może się bronić dość skutecznie. Tak, na moduły TPM też były demonstrowane ataki (fizyczne), ale umówmy się, że stopień złożoności takiego ataku jest nieco większy, niż sprawdzenie wszystkich możliwych kluczy z pewnej niezbyt dużej przestrzeni...
Może czas robić tokeny z gniazdem micro-usb ? Tylko potrzebna natywna obsługa usb host w telefonie a to raczej rzadkość
A jeżeli jesteśmy online to klucz albo jeszcze coś do jego generowania możemy trzymać online.
Problem sprowadza się więc do uwierzytelniania.
Oczywiście przy założeniu że "atakujący ma nieograniczony dostęp do urządzenia i danych na nim przechowywanych" to trudno mówić o jakimkolwiek bezpieczeństwie czegokolwiek.
Immutable Laws of Security
A jeśli chodzi o bankowość, to offline mogą być przechowywane dane informacyjne. Tak, by użytkownik mógł na przykład przeglądać swoją historię operacji bez konieczności połączenia z bankiem.
Jeśli chodzi o uwierzytelnienie, to tu również sprawa może być bardziej skomplikowana. Np. może mieć miejsce skojarzenie konkretnej instancji aplikacji z kontem i samo uwierzytelnienie może odbywać się w sposób prawie niezauważalny dla użytkownika. Użytkownik uwierzytelnia się do swojej lokalnej aplikacji (PIN), po uwierzytelnieniu lokalnym aplikacja sama uwierzytelnia się do banku na przykład z wykorzystaniem "sekretu" rozszyfrowanego przy użyciu klucza wygenerowanego na podstawie kodu PIN lub jakiejś innej metody (np. challenge response).
Kolejna sprawa to autoryzacja transakcji. Bez problemu jestem sobie w stanie wyobrazić implementacje, w której taka aplikacja bankowa będzie miała wbudowany token i będzie prawie automatycznie autoryzowała transakcje. Bo przecież to ma być łatwe, szybkie i wygodne, no nie?
Akurat w przypadku autoryzacji transakcji jestem w stanie wyobrazić sobie również taką implementację, która będzie w stanie się obronić w rozważanym scenariuszu - drugi niezależny PIN służący do "odblokowania" programowego tokenu. Token ZAWSZE generuje odpowiedź, choć oczywiście dla złego kodu PIN odpowiedź będzie zła. Ponieważ wskazanie/odpowiedź tokenu będzie weryfikowane przez serwer pozostający poza kontrolą atakującego możliwe będzie zablokowanie kanału dostępu użytkownikowi, który podał n nieprawidłowych kodów PIN.)
Podsumowując - aplikacja mobilna służąca do dostępu do banku (a co za tym idzie - urządzenie, na którym jest ona zainstalowana) może zawierać w sobie całkiem sporo "konfitur", na których straży stać będzie śmiesznie słaby PIN.
Na szybko można wymienić trzy kwestie związane z bezpieczeństwem mobilnych aplikacji umożliwiających dostęp do usług bankowości:
- ujawnienie danych zawartych w cache,
- uzyskanie możliwości uwierzytelnienia się w systemie bankowości jako ofiara,
- uzyskanie możliwości wykonywania operacji z konta ofiary,
Skutki każdego z tych zdarzeń są oczywiście różne. Przynajmniej przed ostatnim zdarzeniem aplikacja może i powinna się bronić (w rozważanym przeze mnie scenariuszu z pełnym dostępem do urządzenia i danych).
Ogólnie rzecz biorąc bankowe aplikacje mobilne mogą być bardziej "ciekawe" niż systemy bankowości internetowej, bo w tym przypadku atakujący ma pełną kontrolę nad atakowaną aplikacją.
Wrzucę jeszcze jedną sprawę: bardzo często ukradziony/zgubiony telefon będzie włączony, z wszelkimi możliwościami jakie to otwiera (np. odblokowanym magazynem haseł, aktywną aplikacją a nawet jeśli nie, to z obecnymi w pamięci jej danymi). Zamiast wyrzucać sima złodziej może ściągnąć jakąś własną aplikację i ją uruchomić.
PS Mogłyby się pojawić szerzej jakieś nieklawiaturowe techniki wprowadzania haseł. Przyłożenie palca, zrobienie paru gestów czy przyłożenie okienka aparatu do czegośtam nie musi być bardzo kłopotliwe dla usera.