Od wczoraj(?) stało się głośno o firesheep, korzystanie z tego narzędzia opisane jest między innymi tu: Wykradamy sesję użytkownika (Firefox + Firesheep). Odkrywczego tutaj nie ma nic. Przejęcie identyfikatora sesji powoduje (zwykle) przejęcie sesji użytkownika, dlatego identyfikator ten należy chronić. Między innymi poprzez szyfrowanie komunikacji między przeglądarką i serwerem. Opowieści o tym, że jest to bardzo kosztowne obliczeniowo, są "nieco" przesadzone. Warto zapoznać się na przykład z tym tekstem: Overclocking SSL.
Warto się wylogować
Do tego wpisu zainspirował mnie ten komentarz/pytanie:
Niech mi ktoś wytłumaczy jedno: zalogowałem się na FB, zamknąłem przeglądarkę (bez wylogowywania się – Firefox). Włączyłem przeglądarkę ponownie, bez przywracania sesji. Odpaliłem Firesheep i po chwili pojawiło się konto z FB.
Jak ? Firesheep ma chyba przechwytywać sesje aktywne, nie ?
No właśnie, kiedy sesja jest aktywna?
Kiedy sesja jest aktywna
Pytanie dotyczyło FB, ja konta w tym serwisie nie posiadam, ale równie dobrze mogę całą sytuację wytłumaczyć na przykładzie serwisu blip.pl.
W trakcie logowania się do serwisu serwer ustawia cookie z identyfikatorem sesji. Wygląda to tak:
HTTP/1.1 302 Found Date: Wed, 27 Oct 2010 06:09:05 GMT Server: Apache/2.2.3 (Debian) Phusion_Passenger/2.2.11 X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 2.2.11 X-Runtime: 10 Cache-Control: no-cache Set-Cookie: _blip_session=B(...)7; domain=.blip.pl; path=/; HttpOnly Location: http://blip.pl/dashboard Status: 302 Vary: Accept-Encoding Content-Length: 90 Connection: close Content-Type: text/html; charset=utf-8
Tu trzeba zwrócić uwagę na nagłówek Set-Cookie, identyfikator sesji ustawiany jest na sesję użytkownika, ginie on po zamknięciu przeglądarki. Podkreślam: przeglądarki, a nie zakładki (lub w niektórych scenariuszach - okna). Skąd to wiadomo? Po prostu brak jest atrybutu expires.
Tak wcale nie musi być, bo na formatce uwierzytelnienia znajduje się magiczny checkbox Pamiętaj mnie, po którego zaznaczeniu sytuacja nieco się zmienia. Wówczas cookie ustawiane jest w inny sposób:
Set-Cookie: _blip_session=B(...)7; domain=.blip.pl; path=/; expires=Wed, 03-Nov-2010 07:15:04 GMT; HttpOnly
W tym drugim przypadku cookie nie jest usuwane po zamknięciu przeglądarki, a użytkownik jest "logowany automatycznie".
Kiedy sesja jest "aktywna"? Tu sprawa jest nieco skomplikowana, ale w dużym uproszczeniu można powiedzieć, że sesja jest aktywna tak długo, jak istnieje identyfikator sesji.
Istotnym wyjątkiem od tej reguły jest wygasanie sesji. Polega ono na tym, że czas życia sesji jest przedłużany przy każdej aktywności użytkownika. Jeśli użytkownik przez pewien czas nie wykonuje w aplikacji żadnych działań, sesja jest niszczona, a użytkownik proszony jest o ponowne uwierzytelnienie. Mechanizm ten jest powszechnie stosowany w aplikacjach takich jak bankowość internetowa, ale w wielu innych przypadkach - nie. Odwieczny konflikt między wygodą użytkownika a bezpieczeństwem.
Aplikacja powinna udostępniać również mechanizm wylogowania użytkownika. W tym przypadku sesja powinna być niszczona, a użytkownik powinien mieć nawyk wylogowania się z aplikacji. Wylogowania się, a nie "zamykania strony".
Kiedy identyfikator może być wysłany
Drugie nieporozumienie - sesja jest aktywna również wtedy, gdy użytkownik nie ma otwartej strony danego serwisu. Załóżmy, że zalogowałem się do usługi, zobaczyłem co chciałem zobaczyć i poszedłem sobie w zupełnie inne miejsce. Można przypuszczać, że w tym przypadku przeglądarka nie wyśle identyfikatora sesji, bo przecież nie ma ku temu podstaw. Dla wyjaśnienia - przeglądarka wysyła cookie wraz z żądaniem HTTP, jeśli posiada odpowiednie cookie. Odpowiednie, czyli "wystawione" dla odpowiedniej domeny i ścieżki. Szerszego wyjaśnienia tematu należy szukać w opisie Same-origin policy for cookies. Jeśli cookie nie zostanie wysłane, to narzędzia typu firesheep go nie przechwycą, prawda?
Ostatnie zdanie jest prawdziwe - narzędzie nie może znaleźć czegoś, czego nie ma. W szczególności nie może znaleźć identyfikatora sesji w ruchu, jeśli tego identyfikatora tam po prostu nie ma. W wyżej przedstawionym rozumowaniu jest jednak pewien błąd, przeglądarka może wysłać identyfikator sesji (cookie), nawet jeśli użytkownik nie znajduje się na stronie, która "bezpośrednio" wiąże się z serwisem. Dlaczego?
Posłużę się tu przykładem. Co się dzieje, gdy użytkownik wchodzi na mojego bloga? Krótki zrzut z Fiddlera:
Skąd odwołanie do domeny blip.pl? To proste - przez widgety (wklejki, gadżety, ...). A teraz, w dobie tak zwanego Web 2.0, ilość różnych gadżetów na stronie bywa spora (przy okazji przypomnę o kolejnym przykładzie na bootcamp).
Dla porządku, żądanie wysyłane do blip.pl wygląda następująco:
GET http://blip.pl/current_user_status/pgolen HTTP/1.1 Accept: */* Referer: http://wampir.mroczna-zaloga.org/ Accept-Language: pl User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET4.0C; .NET CLR 3.0.30729) Accept-Encoding: gzip, deflate Host: blip.pl Connection: Keep-Alive Cookie: _blip_session=B(...)7;
Tak, chodzi o nagłówek cookie i _blip_session. Nie muszę być na stronie blip.pl, by moja przeglądarka wysłała identyfikator sesji. Na dobrą sprawę mogłem już zapomnieć, że do jakiegoś serwisu się logowałem, nawet wówczas identyfikator sesji może sobie spokojnie żyć, a przeglądarka może go radośnie wysyłać. Efekt? Ta zapomniana sesja może zostać przejęta.
Jak się przed tym bronić?
Nie bardzo jest jak. Aplikacje są napisane tak, jak są napisane. Identyfikatory sesji są wysyłane nieszyfrowanym kanałem, mogą więc być przechwycone i wykorzystane do przejęcia sesji. Oczywiście, można próbować korzystać z wtyczek typu HTTPS Everywhere, ale to rozwiązanie wcale nie musi rozwiązywać problemu, w szczególności SSL może być po prostu niedostępny.
Istnieje jedna dobra praktyka, która co prawda problemu nie rozwiązuje, ale nieco zmniejsza powierzchnię ataku. Zasada jest prosta - sesja nie powinna być aktywna, jeśli z niej nie korzystamy. Ponieważ nie można liczyć na to, że sesja wygaśnie sama, użytkownicy powinni wylogowywać się z aplikacji. A i tak wiem, że robić tego nie będą :)