Jak (prawdopodobnie) działa LastPass
Z materiałów, które na szybko udało mi się przejrzeć (np.: Security Now 256: LastPass Security (notatki), LastPass Gets the Green Light from Security Now!'s Steve Gibson ), wynika, że korzystając z LastPass nie powierzamy swoich haseł chmurze. No, przynajmniej nie w formie jawnej. Po stronie serwera przechowywane dane są szyfrowane z wykorzystaniem (buzzword) AES-256. Ilość danych użytkownika, które przechowywane są w formie jawnej, jest również ograniczona. Można przypuszczać też, że powiązanie danych użytkownika z użytkownikiem jest możliwe tylko wtedy, gdy jest on zalogowany, a tak przynajmniej wynika notatek do podcastu.
Co mogło wyciec
Tu przydatne mogą być informacje zawarte w artykule Exclusive: LastPass CEO Explains Possible Hack.
Najpierw trzeba podkreślić, że cała akcja zaczęła się z powodu przypuszczenia, że mogło dojść do incydentu:
We tend to look over traffic logs and look over what's going on with the networks pretty regularly. Anytime we find any outlier, we want to know why.
Bezpieczeństwo to nie stan (lub produkt), ale proces. Monitorowanie jest jednym z elementów tego procesu i trzeba pochwalić LastPass, że takie monitorowanie ma w ich przypadku miejsce. Dzięki takiemu podejściu można szybko podjąć działania mające na celu ograniczenie skutków incydentu, lub nawet przerwać "pracę" atakującym. Przypuszczam, że teraz po stronie LastPass trwa próba ustalenia tego, czy rzeczywiście coś się stało, a jeśli tak, to co i jak.
Na podstawie ilości danych, które zostały przesłane, przypuszcza się, że wyprowadzone mogły zostać loginy i hasła użytkowników. A konkretnie wyprowadzone mogły zostać:
- nazwy użytkowników (e-mail?),
- hash hasła,
- salt wykorzystany do wyliczenia hasha,
Choć przy uwierzytelnieniu do LastPass należy podać adres e-mail, nie wiem, czy jest on tożsamy z nazwą użytkownika przechowywaną w bazie danych. Równie dobrze w bazie może być przechowywany jego (solony) hash, więc nazwą użytkownika może być nie e-mail, a hash(salt, e-mail), co może mieć pewne znaczenie, ale o tym później. Również istotne/ciekawe jest to, czym jest właściwie hash hasła. Do tego również wrócę za chwilę.
Hands-on lab: jak to działa
Tak jak pisałem wcześniej, w zakresie LastPass jestem (wybitnym) teoretykiem. By to trochę zmienić założyłem sobie konto na LastPass i korzystam z niego przez interfejs webowy.
Logowanie, hash hasła
Co dzieje się w trakcie logowania. Mówię tu o podstawowym typie logowania z wykorzystaniem loginu oraz hasła. Nie korzystam w tym miejscu z żadnych dostępnych w LastPass rozszerzeń. Wygląda na to, że do uwierzytelnienia potrzebne są dwa parametry:
Jak wyliczany jest hash? Jest to SHA256 z nazwy użytkownika (adres e-mail) i jego hasła. A konkretnie:
sha256(sha256(login+password)+password)
Prawdopodobnie te hash pełni rolę hasła. Ciekawe natomiast jak jest przechowywany po stronie serwera. Być może jest wykonywana kolejna operacja SHA256 tym razem składając hash otrzymany od użytkownika z losowym saltem.
Załóżmy, że hash hasła przechowywany w bazie ma postać:
sha256(sha256(sha256(login+password)+password)+salt)
Wygląda mocno, prawda? Tyle tych sha256, że się można pogubić. Czy można próbować łamać hasło użytkownika? Oczywiście, że tak. Pozostaje tylko pytanie jak ciężkie to będzie zadanie.
Salt co do zasady jest przechowywany razem z hashem hasła, przecież system musi mieć możliwość zweryfikowania poprawności podanego hasła, do tego salt jest niezbędny. Jeśli jako login (nazwa użytkownika) używany jest adres e-mail, jedyną niewiadomą jaka pozostaje, jest hasło użytkownika. Sprawdzenie jednego hasła w tym przypadku wymaga wykonania trzech operacji sha256. Dla haseł słownikowych lub prostych haseł nie jest to bariera nie do przejścia.
Wiele razy powtarzałem, że sposób wyliczania hasha hasła powinien być maksymalnie kosztowny obliczeniowo. Nie na tyle kosztowny (czasowo), by irytować użytkownika przed komputerem, ale na tyle, by w przypadku próby łamania hasha offline ilość haseł sprawdzanych w jednostce czasu była jak najmniejsza.
A co by się stało, gdyby hasło (jego hash) było przechowywane w bazie w formie przesyłanej przez klienta, bez ponownego hashowania? Efekt mógłby być taki, jak pokazałem w tym zadaniu (kto rozwiązał, ten wie, kto nie rozwiązał: pass the hash). W rezultacie atakujący mógłby uwierzytelnić się do systemu nie znając hasła użytkownika, uzyskałby tym samym dostęp do zaszyfrowanych blobów, których jednak nie byłby w stanie odszyfrować, bo nie posiadałby klucza.
Buzzword: AES-256
Załóżmy, że AES-256 jest doskonałym algorytmem, nie ma żadnych słabości i rzeczywiście wykorzystuje wszystkie 256 bitów otrzymanego klucza. Stop! Jak generowany jest klucz, którym "wszystkie moje dane" są szyfrowane? Klucz ten jest generowany na podstawie hasła użytkownika. Konkretnie jest to:
SHA256(login+password)
No dobrze, AES może być doskonałym algorytmem, problem w tym, że klucz użyty do szyfrowania zależy wyłącznie od hasła użytkownika, którego złożoność zapewne będzie mniejsza, niż 2^256. Wygenerowanie (prawdopodobnego) klucza dla znanego loginu (adresu e-mail) kosztuje tylko jedną operację SHA256, czyli niezbyt drogo. Oczywiście, jeśli hasło użytkownika jest długie, złożone i niestandardowe, wówczas koszt znalezienia prawidłowego hasła jest duży. W przypadku haseł prostych lub słownikowych znalezienie właściwego klucza/hasła jest możliwe.
Tu wyraźnie widać różnicę między LastPass i KeePass. W przypadku KeePass klucz szyfrowania jest również otrzymywany (między innymi) z wykorzystaniem SHA256 na podstawie hasła użytkownika oraz losowej soli, przy czym ilość rund algorytmu jest większa niż w przypadku LastPass. Więcej szczegółów na ten temat można znaleźć tutaj: Protection against Dictionary Attacks.
Jaki jest efekt tej różnicy? Taki, że sprawdzenie (przetestowanie) jednego hasła jest bardziej kosztowne w przypadku KeePass niż LastPass. Co więcej ilość rund algorytmu generującego klucz szyfrowania jest w przypadku KeePass parametrem konfiguracyjnym. Użytkownik może sam określić jak długo (na jego sprzęcie) powinien generować się klucz. W przypadku LastPass użytkownik takiej możliwości jest pozbawiony. Sam algorytm to nie wszystko, ważny jest jeszcze jego klucz i sposób, w jaki został uzyskany...
Użytkownicy LastPass powinni zapamiętać jedną rzecz. Ich dane NIE SĄ chronione przy pomocy AES-256. Ich dane SĄ chronione przez ich hasło, na podstawie którego generowany jest klucz użyty następnie w AES-256 do zaszyfrowania danych. To siła hasła jest decydująca dla bezpieczeństwa. Dotyczy to nie tylko LastPass, jest to również prawdziwe dla KeePass, TrueCrypt, EFS i wielu innych rozwiązań...
Trochę dziwnych myśli na tematy pokrewne...
Przy okazji można się zastanowić jak długo powinno trwać generowanie klucza na podstawie 16 znakowego hasła (załóżmy, że dostępny alfabet to 62 znaki - duże litery, małe litery i cyfry) by zadanie polegające na wygenerowaniu i sprawdzeniu kluczy dla wszystkich możliwych haseł było porównywalne czasowo do zadania sprawdzenia wszystkich kluczy. Na moim laptopie:
openssl speed aes-256-cbc sha256
Doing sha256 for 3s on 16 size blocks: 3852312 sha256's in 3.00s
Doing sha256 for 3s on 64 size blocks: 2113411 sha256's in 3.00s
Doing sha256 for 3s on 256 size blocks: 915959 sha256's in 2.98s
Doing sha256 for 3s on 1024 size blocks: 283533 sha256's in 2.98s
Doing sha256 for 3s on 8192 size blocks: 38049 sha256's in 3.01s
Doing aes-256 cbc for 3s on 16 size blocks: 8505874 aes-256 cbc's in 3.00s
Doing aes-256 cbc for 3s on 64 size blocks: 2329418 aes-256 cbc's in 2.98s
Doing aes-256 cbc for 3s on 256 size blocks: 595312 aes-256 cbc's in 3.00s
Doing aes-256 cbc for 3s on 1024 size blocks: 240128 aes-256 cbc's in 2.96s
Doing aes-256 cbc for 3s on 8192 size blocks: 30136 aes-256 cbc's in 3.01s
(...)
Załóżmy, że operujemy na blokach wielkości 64 bajtów (hasło to 16 bajtów, do tego jeszcze jakiś salt). Daje to bardzo zbliżoną ilość operacji SHA256 i AES256 wykonywanych w jednostce czasu. A teraz porównajmy przestrzeń (wszystkie hasła o długości 16 znaków ze wskazanego alfabetu i klucz o długości 256 bitów):
62^16: 47672401706823533450263330816 (ilość możliwych haseł)
2^256: 115792089237316195423570985008687907853269984665640564039457584007913129639936 (ilość możliwych kluczy)
I w zasadzie w tej chwili można zakończyć temat. Czas generowania klucza musiałby być (z grubsza) 2428912433432998828466416695673799964348643982483 razy większy, niż czas odszyfrowania bloku danych z wykorzystaniem algorytmu AES. Jak ktoś ma trochę czasu, może sobie dalej policzyć :)
Chyba bardziej sensownym podejściem będzie jednak wyjście od drugiej strony, czyli oszacowanie jak długo powinno trwać generowanie klucza w oparciu o podane hasło, by próba jego łamania (nie mówię o prostych i słownikowych hasłach) była nieopłacalna.
W przypadku 62^16 haseł można oczekiwać, że statystycznie odpowiednie hasło zostanie trafione w 23836200853411766725131665408 próbie (ach te dokładności w przybliżeniach). Posłużę się tu przykładem konfiguracji mojego KeePass. Czas generowania klucza w oparciu o podane hasło to jedna sekunda (na moim sprzęcie). Sprawdzenie tych 23836200853411766725131665408 możliwych haseł zajmie tyleż sekund, co daje:
23836200853411766725131665408 / (60 * 60 * 24 * 365) = 755 840 970 744 919 036 185 LAT
Dla porównania można podać, że wiek wszechświata jest szacowany na 13 600 000 000 lat. Na chwilę obecną mnie trudno jest sobie wyobrazić ilość i wydajność komputerów, które zadanie znalezienia odpowiedniego hasła wykonałyby w czasie, w którym mogłoby mieć to dla mnie znaczenie, optymistycznie określmy go na 100 lat :) Z drugiej strony ciężko powiedzieć jak będzie zmieniała się dostępna technologia w ciągu tego czasu i czy nasza cywilizacja będzie wciąż jeszcze istnieć.
Jak temat będzie się przedstawiał dla takich samych haseł, ale przy sposobie generowania klucza wykorzystanym przez LastPass? Całość zajmie co najmniej 704 470 razy mniej czasu, bo tyle operacji SHA256 w trakcie sekundy jest mniej więcej w stanie wykonać mój system, który wcale nie jest najszybszy. Nadal jest to jednak więcej, niż wiek wszechświata, więc raczej nadal obracamy się w zdarzeniach bardzo mało prawdopodobnych.
Z drugiej strony jeśli ktoś wybierze hasło minimalnej długości (LastPass pozwala na hasło o długości 6 znaków złożone z samych liter), to wówczas cała przestrzeń do przeszukania będzie miała 26^6 elementów, czyli 308915776. Zakładając, że właściwe hasło zostanie znalezione w połowie, daje to 154457888 prób. O ile w (mojej) konfiguracji KeePass zajmie to jakieś cztery lata, to dla klucza generowanego przez LastPass czas wykonania zadania będzie liczył się w minutach.
Moim zdaniem te wartości powinny być bardziej zbalansowane. Minimalne parametry akceptowanego przez system hasła i algorytmy generujące jego hash lub generujące klucz kryptograficzny w oparciu o hasło powinny być tak dobrane, by przynajmniej teoretycznie dla najgorszego przypadku (najłatwiejszego akceptowanego przez system hasła) atak był trochę bardziej kosztowny, niż 5 minut pracy współczesnego komputera średniej klasy.
A co jeśli KTOŚ w LastPass jest ZŁY
Czy LastPass jest w stanie uzyskać dostęp do danych (zaszyfrowanych blobów) przechowywanych przez użytkowników? Dane te są szyfrowane, klucz ma 256 bitów, więc odpowiedź w zasadzie powinna brzmieć: nie - nie ma takiej możliwości. Teoretycznie nie ma różnicy między teorią i praktyką. W praktyce taka różnica jest. W tym przypadku ta różnica sprowadza się (niespodzianka) do klucza.
Przypominam, że w trakcie logowania do LastPass klient przekazuje do serwera:
- login (adres e-mail),
- hash hasła (jak on wygląda, pisałem wcześniej),
Teoretycznie jest to OK, bo nie ma łatwej metody "cofnięcia się" jeden o hash, przypominam:
klucz: sha256(login+password)
hash: sha256(sha256(login+password)+password)
W przypadku słabych haseł ich odgadnięcie jest możliwe. Jeśli ustalone zostanie hasło, wówczas możliwy do wygenerowania jest również klucz użyty do szyfrowania danych przechowywanych na serwerach. W rezultacie odpowiedź powinna brzmieć: tak, LastPass ma możliwość dostępu do danych przechowywanych na swoich serwerach i ich odszyfrowania. Albo jeszcze inaczej - LastPass może w rzeczywistości uzyskać dostęp do danych użytkowników przechowywanych na swoich serwerach w sposób łatwiejszy, niż sugeruje to wykorzystanie AES-256.
To jest jednak dobra chwila, by zejść na ziemię. Jeśli ktoś korzysta z długiego, złożonego hasła, jest raczej bezpieczny. Różnica między poniższymi liczbami:
115792089237316195423570985008687907853269984665640564039457584007913129639936
324518553658426726783156020576256
...może i robi wrażenie, ale trzeba jeszcze zastanowić się nad tym, co one w rzeczywistości znaczą. Co to jest 31536000000? Niewiele, (przybliżona) ilość sekund w 1000 lat.
Z perspektywy ZŁEGO zdecydowanie bardziej efektywnym sposobem uzyskania dostępu do danych użytkowników byłoby wprowadzenie delikatnej zmiany w kodzie (np. aplikacji internetowej) tak, by hasło użytkownika jednak było przesyłane na serwer.
Czy zmiana hasła wystarczy
W wyniku potencjalnego włamania zalecono, by użytkownicy zmienili swoje hasło do LastPass. A przynajmniej ci użytkownicy, których hasło jest "słabe". Czy to wystarczy? Być może, ja bym poszedł jednak krok dalej. Użytkownicy korzystający ze słabych haseł powinni zmienić nie tylko hasło do LastPass, ale również hasła, które w LastPass były przechowywane.
Dlaczego tak uważam? Jeśli jest możliwe odzyskanie hasła, to prawdopodobnie możliwe będzie również wygenerowanie klucza, za pomocą którego dane użytkownika można będzie odszyfrować. Jeśli jednak zaszyfrowane bloby wyciekły, istnieje szansa, że zostaną one odszyfrowane (jeśli ich właściciel korzystał ze słabych haseł). Po prostu zmiana hasła co prawda spowoduje przeszyfrowanie wszystkich aktualnie używanych blobów nowym kluczem otrzymanym z nowego hasła, ale wszystkie kopie zapasowe (i potencjalnie wyprowadzone przez atakujących dane), nadal będą zaszyfrowane starym (słabym) kluczem.
Gdybym miał konto na LastPass, to czy bym się bał
Gdybym miał konto na LastPass, to korzystałbym z długiego i złożonego hasła. Choć zadanie polegające na odgadnięciu mojego hasła będzie prawdopodobnie łatwiejsze, niż trafienie w 256 bitowy klucz, to nadal będzie nieopłacalne i/lub nie do zrealizowania w sensownym czasie. Nie obawiałbym się więc jakoś specjalnie skutków wycieku danych, nawet jeśli wyprowadzona/skradziona (ach te częste backupy) zostałaby cała baza. Nie znaczy to jednak, że nie podjąłbym pewnych środków zaradczych, choćby sukcesywnej zmiany haseł, które były przechowywane w tej bazie. Ale spokojnie, bez pośpiechu...
To, czego bałbym się zdecydowanie bardziej, to jakiś insider w LastPass. Ma zdecydowanie więcej bardziej realnych sposobów na uzyskanie dostępu do moich danych. Na przykład przez drobną modyfikację skryptów...
Wolę korzystać z KeePass, mimo, że w jego wypadku również muszę ufać programiście, że nie popełnił żadnego błędu powodującego, że moje długie i złożone hasła efektywnie i tak generują słabe klucze kryptograficzne, szyfrowanie rzeczywiście szyfruje, a sam program nie wysyła moich kluczy/haseł w tajemnicy przede mną w szeroki świat.
Ja tu jeszcze wrócę...
Do tematu LastPass (aplikacji webowej) jeszcze wrócę. Zapowiadam temat przewodni: snake-oil.
Tylko sama moc hasła to jeszcze nie jedyna możliwość zdyskredytowania aplikacji.
1. Gdy ktoś w LastPass byłby ZŁY - podmiana kodu wtyczki do przeglądarki na taki, który nie robi hasha tylko wysyła plaintext pewnie nie byłaby uciążliwa. Więc dochodzi czynnik zauwania organizacji. Na razie ufam
2. Mam obawy o samą przeglądarkę - pojawia się sporo informacji o 0-dayach, gorzej z tymi, które się nie pojawiają. Ktoś jednak na pwn2own rozwala te najnowsze. A wtedy pewnie dostęp do pamięci procesu i odczytanie hasła nie byłyby problemem.
3. Keylogger na maszynie - zaufanie do komputera.
Podsumowując:
Trochę za dużo kwestii zaufania. Zastanawiam się nad napisaniem czegoś swojego. A do tego czasu - LastPass