Naprawianie / przechwytywanie sesji PHP

145

Próbuję dowiedzieć się więcej o naprawianiu sesji PHP i przechwytywaniu oraz o sposobach zapobiegania tym problemom. Czytałem następujące dwa artykuły na stronie Chrisa Shifletta:

Jednak nie jestem pewien, czy dobrze rozumiem.

Aby zapobiec utrwalaniu sesji, wystarczy wywołać session_regenerate_id (true); po pomyślnym zalogowaniu się kogoś? Myślę, że dobrze to rozumiem.

Mówi również o używaniu tokenów przekazywanych w adresach URL za pośrednictwem $ _GET, aby zapobiec przejmowaniu sesji. Jak by to dokładnie zostało zrobione? Zgaduję, że kiedy ktoś się loguje, generujesz swój token i przechowuje go w zmiennej sesji, a następnie na każdej stronie porównujesz tę zmienną sesji z wartością zmiennej $ _GET?

Czy ten token musiałby być zmieniany tylko raz na sesję czy przy każdym ładowaniu strony?

Czy jest to również dobry sposób na zapobieganie przechwytywaniu bez konieczności przekazywania wartości w adresach URL? byłoby to o wiele łatwiejsze.

me2
źródło
Może mógłbyś dodać linki do stron, na których znalazłeś te rekomendacje.
Gumbo

Odpowiedzi:

219

Ok, są dwa oddzielne, ale powiązane problemy i każdy jest traktowany inaczej.

Utrwalanie sesji

W tym miejscu atakujący jawnie ustawia identyfikator sesji dla użytkownika. Zwykle w PHP robi się to poprzez nadanie im adresu URL takiego jak http://www.example.com/index...?session_name=sessionid. Gdy atakujący przekaże adres URL klientowi, atak jest taki sam, jak atak przejmujący sesję.

Istnieje kilka sposobów zapobiegania utrwalaniu sesji (zrób wszystkie):

  • Ustaw session.use_trans_sid = 0w swoim php.inipliku. To powie PHP, aby nie umieszczał identyfikatora w adresie URL i nie czytał adresu URL dla identyfikatorów.

  • Ustaw session.use_only_cookies = 1w swoim php.inipliku. To powie PHP, aby nigdy nie używał adresów URL z identyfikatorami sesji.

  • Regeneruj identyfikator sesji za każdym razem, gdy zmieni się stan sesji. Oznacza to jedno z poniższych:

    • Uwierzytelnianie użytkownika
    • Przechowywanie poufnych informacji w sesji
    • Zmiana czegokolwiek w sesji
    • itp...

Session Hijacking

Jest to sytuacja, w której osoba atakująca uzyskuje identyfikator sesji i może wysyłać żądania tak, jakby był tym użytkownikiem. Oznacza to, że ponieważ atakujący ma identyfikator, są one praktycznie nie do odróżnienia od prawidłowego użytkownika w odniesieniu do serwera.

Nie można bezpośrednio zapobiec przejmowaniu sesji. Możesz jednak podjąć kroki, aby uczynić go bardzo trudnym i trudniejszym w użyciu.

  • Użyj silnego identyfikatora skrótu sesji: session.hash_functionw php.ini. Jeśli PHP <5.3, ustaw session.hash_function = 1na SHA1. Jeśli PHP> = 5.3, ustaw na session.hash_function = sha256lub session.hash_function = sha512.

  • Wyślij silny hash: session.hash_bits_per_characterin php.ini. Ustaw to na session.hash_bits_per_character = 5. Chociaż nie utrudnia to złamania, ma znaczenie, gdy atakujący próbuje odgadnąć identyfikator sesji. Identyfikator będzie krótszy, ale zawiera więcej znaków.

  • Ustaw dodatkową entropię z session.entropy_filei session.entropy_lengthw php.inipliku. Na przykład ustaw pierwszy na, session.entropy_file = /dev/urandoma drugi na liczbę bajtów, które zostaną odczytane z pliku entropii session.entropy_length = 256.

  • Zmień nazwę sesji z domyślnego PHPSESSID. Osiąga się to przez wywołanie session_name()z własną nazwą identyfikatora jako pierwszym parametrem przed wywołaniem session_start.

  • Jeśli jesteś naprawdę paranoikiem, możesz również obrócić nazwę sesji, ale uważaj, że wszystkie sesje zostaną automatycznie unieważnione, jeśli to zmienisz (na przykład, jeśli uzależnisz to od czasu). Ale w zależności od przypadku użycia może to być opcja ...

  • Często zmieniaj identyfikator sesji. Nie robiłbym tego przy każdym żądaniu (chyba że naprawdę potrzebujesz tego poziomu bezpieczeństwa), ale w losowych odstępach czasu. Chcesz to często zmieniać, ponieważ jeśli napastnik przejmie sesję, nie chcesz, aby mógł z niej korzystać zbyt długo.

  • Uwzględnij klienta użytkownika z$_SERVER['HTTP_USER_AGENT'] sesji. Zasadniczo, gdy sesja się rozpocznie, zapisz ją w czymś podobnym $_SESSION['user_agent']. Następnie przy każdym kolejnym żądaniu sprawdź, czy pasuje. Zauważ, że można to sfałszować, więc nie jest to w 100% wiarygodne, ale lepiej niż nie.

  • Uwzględnij adres IP użytkownika z$_SERVER['REMOTE_ADDR'] sesji. Zasadniczo, gdy sesja się rozpocznie, zapisz ją w czymś podobnym $_SESSION['remote_ip']. Może to być problematyczne w przypadku niektórych dostawców usług internetowych, którzy używają wielu adresów IP dla swoich użytkowników (na przykład AOL). Ale jeśli go użyjesz, będzie znacznie bezpieczniejszy. Jedynym sposobem na sfałszowanie adresu IP przez napastnika jest włamanie się do sieci w pewnym momencie między rzeczywistym użytkownikiem a Tobą. A jeśli włamą się do sieci, mogą zrobić o wiele gorzej niż przejęcie (takie jak ataki MITM itp.).

  • Dołącz token do sesji i po stronie przeglądarek, które często zwiększasz i porównujesz. Zasadniczo dla każdego żądania wykonaj $_SESSION['counter']++po stronie serwera. Zrób też coś w JS po stronie przeglądarki, aby zrobić to samo (używając lokalnej pamięci). Następnie, kiedy wysyłasz żądanie, po prostu weź wartość jednorazową tokena i sprawdź, czy liczba jednorazowa jest taka sama na serwerze. W ten sposób powinieneś być w stanie wykryć przejętą sesję, ponieważ atakujący nie będzie miał dokładnego licznika, a jeśli tak, będziesz mieć 2 systemy transmitujące tę samą liczbę i możesz stwierdzić, że jeden jest sfałszowany. To nie zadziała w przypadku wszystkich aplikacji, ale jest jednym ze sposobów rozwiązania problemu.

Uwaga na temat dwóch

Różnica między utrwalaniem sesji a przejęciem polega tylko na tym, w jaki sposób identyfikator sesji jest zagrożony. W fiksacji identyfikator jest ustawiany na wartość, którą napastnik zna wcześniej. W Hijacking jest albo odgadnięty, albo skradziony użytkownikowi. W przeciwnym razie skutki obu są takie same, gdy identyfikator zostanie naruszony.

Regeneracja identyfikatora sesji

Zawsze, gdy ponownie generujesz identyfikator sesji przy użyciu session_regenerate_idstarej sesji, należy go usunąć. Dzieje się to w sposób przejrzysty w przypadku podstawowego programu obsługi sesji. Jednak niektóre niestandardowe programy obsługi sesji używająsession_set_save_handler() tego nie robią i są narażone na atak na stare identyfikatory sesji. Upewnij się, że jeśli używasz niestandardowej procedury obsługi sesji, śledzisz otwierany identyfikator, a jeśli nie jest to ten sam, który zapisujesz, jawnie usuwasz (lub zmieniasz) identyfikator ze starego.

Używając domyślnego programu obsługi sesji, wystarczy tylko wywołać session_regenerate_id(true). Spowoduje to usunięcie starych informacji o sesji. Stary identyfikator nie jest już ważny i spowoduje utworzenie nowej sesji, jeśli osoba atakująca (lub ktokolwiek inny w tej sprawie) spróbuje go użyć. Uważaj jednak na niestandardowe programy obsługi sesji ....

Niszczenie sesji

Jeśli masz zamiar zniszczyć sesję (na przykład podczas wylogowania), upewnij się, że zniszczyłeś ją dokładnie. Obejmuje to wyłączenie pliku cookie. Używając session_destroy:

function destroySession() {
    $params = session_get_cookie_params();
    setcookie(session_name(), '', time() - 42000,
        $params["path"], $params["domain"],
        $params["secure"], $params["httponly"]
    );
    session_destroy();
}
ircmaxell
źródło
4
Użycie 5 zamiast 4 bitów na znak w żaden sposób nie zmienia „siły” (cokolwiek „siła” oznacza w tym przypadku). Ale chociaż twoje uwagi są ogólnie rzecz biorąc wskazane, brakuje im niektórych ważnych szczegółów. Na przykład, co dzieje się z sesją, która jest powiązana ze starym identyfikatorem sesji lub jak powinna być obsługiwana sesja ze starym identyfikatorem sesji, gdy stała się nieważna.
Gumbo
2
@battal: Nie, o to chodzi. session_regenerate_idnie unieważnia sesji, która jest nadal powiązana ze starym ID; tylko jeśli parametr delete_old_session ma wartość true, sesja zostanie zniszczona. Ale co, jeśli osoba atakująca zainicjowała regenerację identyfikatora?
Gumbo
6
Nie zgadzam się z regeneracją sesji za każdym razem, gdy zmieniasz zmienną sesji, powinno to być wykonywane tylko podczas logowania / wylogowywania. Również sprawdzenie klienta użytkownika jest bez znaczenia, a sprawdzenie REMOTE_ADDR jest problematyczne. Jedna rzecz, którą chciałbym dodać, to session.entropy_file = /dev/urandom. Udowodniono, że wewnętrzna generacja entropii w PHP jest wyjątkowo słaba, a pula entropii dostarczana przez / dev / random lub / dev / uranom jest najlepszą, jaką można uzyskać na serwerze WWW bez sprzętowego rng.
wieża
4
Powinieneś także dodać session.cookie_httponlyi session.cookie_secure. Pierwsza z nich pomaga udaremnić xss (ale nie jest doskonała). Drugie miejsce to najlepszy sposób na zatrzymanie OWASP A9 ...
wieża
4
Nie rozumiem tak świetnej odpowiedzi, ale brakuje najważniejszego elementu: użyj SSL / HTTPS. Przyrost licznika jest źródłem problemu z wieloma żądaniami szybko po sobie, użytkownik dwukrotnie odświeża stronę lub dwukrotnie naciska przycisk przesyłania. Rozwiązanie adresu IP jest obecnie problemem dla wszystkich użytkowników mobilnych i ciągle zmieniających się adresów IP. Możesz spojrzeć na pierwszy zestaw adresów IP, ale nadal prosi o kłopoty. Najlepszym rozwiązaniem jest zapobieganie wykryciu identyfikatora sesji w pierwszej kolejności i używanie SSL / HTTPS.
Sanne
37

Oba ataki sesyjne mają ten sam cel: uzyskać dostęp do legalnej sesji innego użytkownika. Ale wektory ataku są różne:

  • W ataku typu Session Fixation atakujący ma już dostęp do ważnej sesji i próbuje zmusić ofiarę do skorzystania z tej konkretnej sesji.

  • W ataku „ Session Hijacking ” napastnik próbuje uzyskać identyfikator sesji ofiary, aby użyć jej / jej sesji.

W obu atakach identyfikator sesji jest poufnymi danymi, na których koncentrują się te ataki. Jest to więc identyfikator sesji, który musi być chroniony zarówno dla dostępu do odczytu (przechwytywanie sesji), jak i dostępu do zapisu (utrwalenie sesji).

W tym przypadku obowiązuje również ogólna zasada ochrony wrażliwych danych przy użyciu protokołu HTTPS. Dodatkowo wykonaj następujące czynności:

Aby zapobiec atakom Session Fixation , upewnij się, że:

Aby zapobiec atakom typu Session Hijacking , upewnij się, że:

Aby zapobiec atakom obu sesji, upewnij się, że:

  • akceptować tylko sesje zainicjowane przez Twoją aplikację. Możesz to zrobić, pobierając odciski palców sesji podczas inicjowania z informacjami specyficznymi dla klienta. Możesz użyć identyfikatora User-Agent, ale nie używaj zdalnego adresu IP ani żadnych innych informacji, które mogą się zmieniać między żądaniami.
  • do zmiany identyfikatora sesji przy użyciu session_regenerate_id(true)po próbie uwierzytelnienia ( truetylko w przypadku pomyślnej) lub zmiany uprawnień i zniszczenia starej sesji. (Upewnij się, aby zapisać zmiany z $_SESSIONużyciem session_write_close wcześniej Jeśli chcesz zachować sesję skojarzoną ze starym identyfikatorem, wygenerowaniem identyfikatora; w przeciwnym razie te zmiany wpłyną tylko na sesję z nowym identyfikatorem).
  • aby użyć właściwej implementacji wygasania sesji (zobacz Jak wygaśnąć sesję PHP po 30 minutach? ).
Gumbo
źródło
Świetny post, zwłaszcza ostatnia sekcja.
Mattis
6

Żetony, o których wspomniałeś, są jednorazowymi numerami. Niekoniecznie muszą być używane tylko raz, ale im dłużej są używane, tym większe jest prawdopodobieństwo, że nonce można przechwycić i wykorzystać do przejęcia sesji.

Inną wadą wartości nonces jest to, że bardzo trudno jest zbudować system, który ich używa i zezwala na wiele równoległych okien w tej samej formie. np. użytkownik otwiera dwa okna na forum i zaczyna pracę nad dwoma postami:

window 'A' loads first and gets nonce 'P'
window 'B' loads second and gets nonce 'Q'

Jeśli nie masz możliwości śledzenia wielu okien, zachowasz tylko jedną wartość jednorazową - wartość okna B / Q. Gdy użytkownik następnie prześle swój post z okna A i przejdzie jednorazowo „P”, system ten odrzuci wiadomość jako P != Q.

Marc B.
źródło
Więc co to ma wspólnego z utrwalaniem sesji?
wieża
2
Ma ważny punkt, szczególnie w dziedzinie używania wielu żądań AJAX jednocześnie.
DanielG,
2

Nie czytałem artykułu Shiflett, ale myślę, że coś źle zrozumiałeś.

Domyślnie PHP przekazuje token sesji w adresie URL, gdy klient nie akceptuje plików cookie. W najczęstszym przypadku token sesji jest przechowywany jako plik cookie.

Oznacza to, że jeśli umieścisz token sesji w adresie URL, PHP rozpozna go i spróbuje go później użyć. Naprawianie sesji ma miejsce, gdy ktoś tworzy sesję, a następnie nakłania innego użytkownika do współużytkowania tej samej sesji, otwierając adres URL zawierający token sesji. Jeśli użytkownik uwierzytelnia się w jakiś sposób, złośliwy użytkownik zna token sesji uwierzytelnionego użytkownika, który może mieć różne uprawnienia.

Jak na pewno Shiflett wyjaśnia, zwykłą czynnością jest ponowne generowanie innego tokena za każdym razem, gdy zmieniają się uprawnienia użytkownika.

Andrea
źródło
Aby to dodać, pamiętaj o zniszczeniu wszystkich wcześniej otwartych sesji, ponieważ będą one nadal ważne z istniejącymi uprawnieniami użytkownika.
Corrodedmonkee
0

Tak, możesz zapobiec utrwalaniu sesji, ponownie generując identyfikator sesji po zalogowaniu. W ten sposób, jeśli atakujący nie będzie znał wartości cookie nowo uwierzytelnionej sesji. Inne podejście, które całkowicie zatrzymuje problem, jest ustawione session.use_only_cookies=Truew konfiguracji środowiska wykonawczego. Osoba atakująca nie może ustawić wartości pliku cookie w kontekście innej domeny. Fiksacja sesji polega na wysłaniu wartości pliku cookie jako GET lub POST.

wieża
źródło