3. Błędy uwierzytelnienia i kontroli sesji

Kontynuując temat rozpoczęty w poprzednim rozdziale przyjrzyjmy się innym rodzajom błędów związanych z uwierzytelnieniem użytkowników.

Pierwszym z nich jest wykorzystanie domyślnych poświadczeń i kont użytkowników w systemach i aplikacjach. Prosta analiza prób włamań do systemów operacyjnych z rodziny Linux-a pokazuje, że bardzo często sprawdzane nazwy użytkowników obejmują typowe usługi i konta systemowe jak admin, apache2, ftp, ipc, backup, mysql, postgres, proxy, root, sync, upload, uucp a także powiązane z wieloma typowymi dystrybucjami i narzędziami jak ubuntu, bitnami, advantage, azureuser, cactiuser, cassandra, centos, huawei, tempuser, user0 etc. (na podstawie własnych analiz).

Domyślne konta użytkowników można wykorzystać m.in. do ataku na router domowy w celu zmiany ustawień serwera DNS i przekierowywania ofiary na podstawione strony www (CVE-2013-2645) [19].

Zabezpieczeniem przed atakami brute-force może być ograniczenie ilości poprawnie wykonywanych prób uwierzytelnienia w jednostce czasu (np. zezwalamy na k prób w ciągu N minut, a następnie przez następne X minut próby, nawet poprawne zostaną zignorowane). Ogranicza to skuteczność ataku nie powodując dodatkowego obciążenia serwera. Uwaga: alternatywna technika spowalniania reakcji wraz ze wzrostem liczby prób konsumuje zasoby serwera ułatwiając atak typu DoS (denial-of-service). Z drugiej strony znaczącym ułatwieniem dla atakującego jest nieprawidłowe sygnalizowanie powodu błędu uwierzytelnienia – komunikat błędu nie powinien wskazywać powodu odrzucenia danych uwierzytelniających a dodatkowo czas potrzebny na wygenerowanie komunikatu nie powinien zależeć od rodzaju błędu (side-channel). Wiedza o tym, czy dane konto istnieje czy nie jest istotna z punktu widzenia procesu poszukiwania hasła.

Jednym z bardziej skutecznych sposobów ograniczania skuteczności ataków na hasła użytkowników jest stosowanie uwierzytelnienia wieloetapowego. Dodanie dodatkowych komponentów do procesu uwierzytelnienia zgodnie z zasadą:

  • coś co znam (hasło),
  • coś co mam (token sprzętowy, aplikacja generująca kod, karta inteligentna),
  • coś czym jestem (biometria),

znacząco utrudnia lub wręcz uniemożliwia obejście procesu uwierzytelnienia prostymi metodami. Więcej o tematyce obchodzenia zabezpieczeń wieloetapowych można przeczytać w książce [20].

Kolejnym problemem jest utrzymywanie i ujawnianie danych sesji uwierzytelnionej poprzez

  • ujawnianie identyfikatorów sesji w pasku adresu URL przeglądarki, co umożliwia podejrzenie identyfikatora przez osoby postronne lub ujawnienie na filmie/zdjęciu. Ujawnienie identyfikatorów sesji może prowadzić do jej przejęcia przez atakującego – Session Hijacking,
  • zaniechanie zmiany identyfikatora sesji po uwierzytelnieniu użytkownika – niezaufany identyfikator staje się zaufany, co w przypadku jego poznania przed uwierzytelnieniem prowadzi do jednego z wariantów ataku Session Fixation,
  • przewidywalne identyfikatory sesji,
  • brak unieważniania identyfikatora sesji po wylogowaniu (częsty błąd przy wykorzystaniu tokenów JWT),
  • możliwość wymuszenia znanego identyfikatora sesji poprzez podanie go jako ciasteczko, identyfikator w URL, efekt ataku cross-site scripting – przy braku regeneracji identyfikatora przy uwierzytelnieniu umożliwia drugi wariant ataku Session Fixation.

Przykład podstawienia identyfikatora sesji w JavaScript:

<script>document.cookie="JSESSIONID=32784652376453764573645";</script>
lub jako tag HTML (HTML injection):

<meta http−equiv=Set−Cookie content="PHPSESSID=3278465237645376"/>

Metodami obrony w tym przypadku są:

  • regeneracja identyfikatora sesji przy każdej zmianie poziomu uprawnień, a nawet co ustalony czas,
  • ukrycie identyfikatora sesji przed kodem JavaScript poprzez użycie atrybutu HttpOnly dla ciasteczka,
  • używanie nieprzewidywalnych, losowych identyfikatorów sesji o długości >=128 bitów,
  • w przypadku sesji podlegających wymaganiom PCI DSS 3.2 czas życia identyfikatora do regeneracji <= 15min,
  • skuteczne unieważnianie identyfikatora sesji po wylogowaniu – w przypadku tokenów JWT oznacza to przechowywanie unieważnionych tokenów do upływu ich zdefiniowanego czasu życia.

Dobrym zaleceniem w kontekście przejmowania sesji jest też uniemożliwienie posiadania wielu równoległych sesji dla tego samego użytkownika, a jeżeli aplikacja to umożliwia to warto dać użytkownikowi możliwość sprawdzenia jakie uwierzytelnione sesje posiada (patrz ekosystem Google).