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 = 0
w swoim php.ini
pliku. To powie PHP, aby nie umieszczał identyfikatora w adresie URL i nie czytał adresu URL dla identyfikatorów.
Ustaw session.use_only_cookies = 1
w swoim php.ini
pliku. 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_function
w php.ini
. Jeśli PHP <5.3, ustaw session.hash_function = 1
na SHA1. Jeśli PHP> = 5.3, ustaw na session.hash_function = sha256
lub session.hash_function = sha512
.
Wyślij silny hash: session.hash_bits_per_character
in 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_file
i session.entropy_length
w php.ini
pliku. Na przykład ustaw pierwszy na, session.entropy_file = /dev/urandom
a 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_id
starej 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();
}