2FA czasem zawodzi
Tak, uwierzytelnienie 2FA nie jest nie do przejścia dla atakujących i w związku z tym można przeczytać takie artykuły: Chinese Hackers Bypass 2FA in Attacks Spanning 10 Countries. Warto zdawać sobie sprawę ze sposobów, w jaki 2FA może zawieść (innymi słowy – warto wiedzieć jak inni zepsuli 2FA).
Sposobów jest kilka, na początek warto zastanowić się nad tymi obszarami:
- jak wygląda proces inicjalizowania 2FA;
- jak działa dane 2FA (czym jest ten drugi składnik);
- jak użytkownicy rozumieją czego się od nich oczekuje (jak 2FA powinno działać);
- jak obsługiwane są „zdarzenia brzegowe” typu utrata drugiego składnika lub dodanie kolejnego składnika.
Ta lista oczywiście nie jest kompletna, ale na początek jest wystarczająca.
Inicjowanie 2FA
Jednym z typowych scenariuszy jest aktywacja uwierzytelnienia dwuskładnikowego, a konkretniej skojarzenie drugiego składnika z kontem użytkownika.
Wiele rozwiązań 2FA oparte jest na kodach jednorazowych wyliczanych na podstawie określonego algorytmu z wykorzystaniem pewnego sekretu dzielonego między serwerem i użytkownikiem. W wielu przypadkach ten algorytm to HMAC-based One-time Password algorithm i, o ile ktoś nie stara się go zaimplementować w „twórczy i kreatywny” sposób, sam algorytm jest bezpieczny. Większym problemem jest ustalenie wspomnianego sekretu.
Wspomniany sekret można uzgodnić na wiele sposobów i można to zrobić w sposób bezpieczny i przyjazny dla użytkownika. Nie chcę generalizować, ale do pewnego stopnia im nowsze rozwiązanie, tym lepiej. Dlaczego? Dlatego, że sprzęt poszedł do przodu, wymiana sekretu może być oparta o kody QR i/lub dialog między aplikacją implementującą 2FA i serwerem, oba podejścia pozwalają na uzgodnienie długiego, losowego sekretu. W starszych rozwiązaniach ustalanie sekretu odbywało się za pośrednictwem „interfejsu białkowego”, czyli (najczęściej nieświadomego) użytkownika, dla którego wygody często wykorzystywany był „kod aktywacyjny” składający się z 6, 8 lub 9 cyfr. Jeśli jest to tymczasowy kod, który wykorzystywany jest „pod spodem” do ustalenia właściwego sekretu, nie jest to problemem, ale co jeśli ten kod jest bezpośrednio przekształcany w sekret? Ile możliwych wartości daje 9 cyfr? Ile to bitów?
Może i 1 000 000 000 możliwych wartości sekretu (seed) to więcej niż ilość użytkowników, którzy z danego rozwiązania będą korzystać, ale 30 bitów to po prostu za mało i realne jest przygotowanie sekwencji kodów OTP dla wszystkich (a przynajmniej znaczącej części możliwych wartości seed), zidentyfikowanie konkretnego seed na podstawie sekwencji kilku kolejnych kodów OTP co w rezultacie efektywnie skutkuje „sklonowaniem” takiego tokenu 2FA.
Tak, inicjalizacja 2FA jest zdecydowanie pierwszym obszarem, który należy dokładnie przeanalizować.
A w zasadzie jak działa ten drugi składnik
To jest bardzo szerokie zagadnienie i nie ogranicza się wyłącznie do tematu algorytmu używanego do generowania OTP, w zasadzie można zacząć od pytania czym jest ten drugi składnik. Pomijając biometrię możemy mieć do czynienia z dwoma głównymi scenariuszami:
- dedykowanym urządzeniem służącym jako drugi składnik;
- wykorzystaniem “general purpose device” jako drugiego składnika.
Dedykowane urządzenie z reguły jest bezpieczniejsze, ale przy tym nie zawsze wygodne. Zresztą z tym bezpieczeństwem też bywa różnie, bo ilość sposobów na interakcję z takim urządzeniem rośnie, często nie jest to już kod wyświetlany na wyświetlaczu, urządzenie może być podłączone do innych urządzeń korzystając z portów (np. USB), Bluetooth czy NFC. W efekcie rosnącej złożoności można potem oglądać takie informacje: Google Will Replace Titan Security Key Over a Bluetooth Flaw, ciekawą lekturą może być również sekcja Security Advisories dla Yubico.
Pod względem (nie)bezpieczeństwa zdecydowanie ciekawsze są aplikacje na telefony. Z ciekawszych zagadnień warto wspomnieć:
- jak sekret jest przechowywany na urządzeniu;
- czy interakcja z użytkownikiem jest wymagana do wygenerowania kodu / przeprowadzenia uwierzytelnienia;
- czy kod może być wygenerowany w sposób automatyczny przez inną aplikację.
Zarówno Android jak i iOS oferują obecnie bezpieczne sposoby przechowania sekretów i rozwiązania te działają dość dobrze, przynajmniej do czasu, gdy integralność systemu nie zostaje naruszona (rooting / jailbreak). Zdecydowanie więcej „radości” dają sytuację, gdy sekret (seed) przechowywany jest „lokalnie” i jest zabezpieczony w sposób wymyślony przez autorów aplikacji.
Tutaj trzeba pamiętać, że nawet posiadanie seeda z urządzenia niekoniecznie oznacza możliwość generowania prawidłowych kodów OTP, bo w procesie tworzenia OTP może być uwzględniany sekret pochodzący od użytkownika (np. dodatkowy PIN). Teoretycznie nawet stosunkowo krótki PIN (np. 6 cyfr) będzie wystarczający, pod warunkiem, że sekret będzie blokowany po wielokrotnym błędnym podaniu kodu.
Jak można to zepsuć? Proste – pozwolić atakującemu na „łamanie” PIN offline. By to było możliwe potrzebny jest jakiś sposób weryfikacji poprawności kodów OTP, na przykład:
- historia wygenerowanych kodów OTP (pliki logów, podsłuchana komunikacja);
- seed jest przechowywany w formie zaszyfrowanej, przy czym dane mają określoną strukturę (np. zaszyfrowanie seed szyfrem blokowym w trybie CBC z paddingiem);
- seed jest przechowywany w formie zaszyfrowanej, klucz szyfrowania jest generowany na podstawie obecnego kodu PIN, przy zmianie kodu PIN następuje zaszyfrowanie seed nowym kluczem, a na urządzeniu pozostaje również stara wersja zaszyfrowanego seed.
Ale dajmy już spokój takim niskopoziomowym atakom, czasami po prostu wystarczy poprosić aplikację o wygenerowanie kodu OTP. Aplikacja „tokena” może dla wygody użytkownika pozwalać innym aplikacjom na generowanie i otrzymywanie kodów. Samo w sobie nie jest to złe, pod warunkiem, że:
- ta możliwość jest ograniczona do konkretnych aplikacji (np. konkretnego banku);
- wygenerowanie kodu wymaga akcji użytkownika i użytkownik wie gdzie trafi wygenerowany kod.
Jak można zepsuć to w sposób spektakularny? Sytuacja, w której token jest „odblokowywany” po pierwszym podaniu kodu PIN (czyli przy kolejnych prośbach o kod OTP użytkownik nie jest proszony o podanie kodu PIN) i zezwolenie dowolnej aplikacji na poproszenie o kod OTP nie jest najlepszym pomysłem.
Nie zapominajmy, że na końcu mamy aplikację, do której się uwierzytelniamy. Być może wcale nie trzeba się skupiać na sposobie działania 2FA, ale na procesie uwierzytelnienia w aplikacji. Coraz częściej proces ten składa się z wielu kroków z wieloma przekierowaniami oraz potencjalnie różnymi ścieżkami wykonania, bo przecież:
- nie każdy użytkownik musi mieć aktywowane 2FA;
- nie każdy użytkownik musi korzystać z tej samej metody 2FA;
- być może użytkownik korzysta z funkcji „przywracania” 2FA;
- być może (...).
Im bardziej skomplikowany jest proces, tym większe prawdopodobieństwo błędu. Co się stanie, gdy jeden lub kilka kroków tego procesu zostanie pominiętych lub wykonanych w nieoczekiwanej kolejności?
Pytają, to podam
2FA jest rozwiązaniem technicznym a rozwiązania techniczne nie są w stanie poradzić sobie z kreatywnością (właściwie – ignorancją) użytkowników. Można to tłumaczyć jako typowy przykład PEBCAK, albo zaprojektować system w taki sposób, by był zrozumiały dla użytkownika oraz by zachowanie niezgodne z oczekiwaniami było dla użytkownika „trudne”, czyli wymagało jakiegoś wysiłku, który być może skłoni go do refleksji.
Tradycyjne kody jednorazowe (np. hardware token) w żaden sposób nie są powiązane z inną akcją wykonaną przez użytkownika, kod OTP jest wyświetlany przez urządzenie niezależnie od akcji użytkownika, a użytkownik w wielu wypadkach jest proszony o jego podanie. Phishing to też nic innego, jak próba skłonienia użytkownika do określonej akcji, a wielkiej różnicy między podaniem hasła a kodu OTP tak naprawdę nie ma.
Tu warto zastanowić się, czy:
- 2FA związane jest z kontekstem (zachowaniem lub akcją) wykonaną przez użytkownika;
- czy użytkownik jest w stanie zrozumieć jaka jego akcja spowodowała prośbę o podanie drugiego składnika;
- czy atakujący jest w stanie poprosić użytkownika o podanie drugiego składnika w przekonywujący sposób;
- czy użytkownik ma szansę zorientowania się, że będzie potwierdzał akcję, której nie zainicjował.
Tutaj dość dobrze sprawdzają się aplikacje na telefonach, które reagują na akcję użytkownika w aplikacji (często oparte jest to na powiadomieniach PUSH). Na przykład w procesie uwierzytelnienia użytkownik jest proszony o potwierdzenie próby logowania na urządzeniu, na którym jednocześnie pojawia się stosowny komunikat z dodatkowymi informacjami o akcji, która zostanie potwierdzona.
Przykładem takiego rozwiązania może być Microsoft Authenticator. Trochę inaczej działają rozwiązania Apple, ale tam również jest informacja o zdarzeniu (próba uwierzytelnienia) oraz geolokacja.
Zgubiłem (...), możecie wyłączyć 2FA?
No i tutaj zaczyna robić się naprawdę ciekawie. Sam kiedyś miałem problem z MFA używanym w Amazon (Google Authenticator) gdy telefon odmówił współpracy. I co wtedy? Wówczas wystarczyło zgłoszenie problemu, po pewnym czasie na mój numer telefonu zadzwonił miły pan, który zapytał co się stało, bardzo zmartwił się moim problemem z telefonem i... wyłączył 2FA na moim koncie. Tak, wiem. Teraz ten proces uległ zmianie i wygląda nieco inaczej, ale czy na pewno dużo lepiej?
Po co atakować (mocne) 2FA jeśli można użyć innej, mniej bezpiecznej metody? Często używane „zapasowe metody” to:
- lista kodów jednorazowych;
- numer telefonu (kod przesyłany SMS lub przez voice message);
- zapasowy adres e-mail.
Co lepiej (gorzej) często skonfigurować trzeba wszystkie te metody. Dlaczego gorzej? Bo o ile lista kodów jednorazowych może być dość dobrze chroniona fizycznie to co z telefonem lub mailem?
Najpierw SMS / wiadomość głosowa – jeśli SMS sam w sobie nie jest uważany za bezpieczną metodę przekazywania haseł jednorazowych to nie staje się on bezpieczny, gdy jest używany jako backup dla innego, bardziej bezpiecznego rozwiązania.
A co z mailem? To zależy, czy na tym adresie też jest aktywowane 2FA? Jeśli tak, to „(...) by zrozumieć rekurencję należy najpierw zrozumieć rekurencję (...)”.
Podobne wyzwania są z zarządzaniem 2FA. Pytanie – czy jeśli atakujący przejmie aktywną sesję użytkownika jest on w stanie zmienić konfigurację 2FA, na przykład:
- wyłączyć 2FA na koncie;
- dodać dodatkowe urządzenie 2FA?
Co zrobić, jak żyć?
Po pierwsze – rozwiązania 2FA, nawet jeśli nie są doskonałe, są lepsze niż 1FA (brak 2FA). Nawet 2FA, które jest słabe (wspomniane SMS) jest lepsze niż jego kompletny brak i dla części zastosowań może być wystarczające.
Po drugie – warstwy. Użytkownik powinien być informowany o potencjalnie istotnych zdarzeniach, a zdarzenia związane z uwierzytelnieniem są istotne. Zalicza się do nich nie tylko udane lub nieudane uwierzytelnienie (przy okazji – im więcej szczegółów o tych zdarzeniach, tym lepiej), ale również wszelkie zdarzenia związane z zarządzaniem kontem (np. próba resetu hasła, próba resetu 2FA).
Kilka słów na koniec
- Tak, wiem, MFA i 2FA to nie jest to samo;
- Tak, wiem, niektóre z metod wymienionych wyżej nie do końca spełniają definicję 2FA;
- Tak, wiem, nie każde rozwiązanie 2FA to token i nie każde jest oparte o OTP.
Oryginał tego wpisu dostępny jest pod adresem 2FA czasem zawodzi
Autor: Paweł Goleń