Bezpieczeństwo sesji PHP

125

Jakie są wskazówki dotyczące utrzymywania odpowiedzialnego bezpieczeństwa sesji w PHP? W całej sieci są informacje i najwyższy czas, aby wylądowały w jednym miejscu!

saint_groceon
źródło

Odpowiedzi:

88

Aby zapewnić bezpieczeństwo sesji, należy wykonać kilka czynności:

  1. Używaj SSL do uwierzytelniania użytkowników lub wykonywania wrażliwych operacji.
  2. Regeneruj identyfikator sesji po każdej zmianie poziomu zabezpieczeń (np. Przy logowaniu). Jeśli chcesz, możesz nawet wygenerować identyfikator sesji przy każdym żądaniu.
  3. Wyznacz sobie limit czasu sesji
  4. Nie używaj register globals
  5. Przechowuj szczegóły uwierzytelniania na serwerze. Oznacza to, że nie wysyłaj w pliku cookie szczegółów, takich jak nazwa użytkownika.
  6. Sprawdź $_SERVER['HTTP_USER_AGENT']. To dodaje niewielką barierę do przechwytywania sesji. Możesz również sprawdzić adres IP. Ale powoduje to problemy dla użytkowników, którzy mają zmieniający się adres IP z powodu równoważenia obciążenia na wielu połączeniach internetowych itp. (Co ma miejsce w naszym środowisku tutaj).
  7. Zablokuj dostęp do sesji w systemie plików lub użyj niestandardowej obsługi sesji
  8. W przypadku operacji wrażliwych rozważ wymóg ponownego podania danych uwierzytelniania zalogowanych użytkowników
grom
źródło
15
Używanie SSL tylko do niektórych operacji nie wystarczy, chyba że masz oddzielne sesje dla ruchu szyfrowanego i niezaszyfrowanego. Jeśli korzystasz z pojedynczej sesji przez HTTPS i HTTP, atakujący wykradnie ją przy pierwszym żądaniu innym niż HTTPS.
Kornel
6
-1 klient użytkownika jest trywialny do sfałszowania. To, co opisujesz, kod odpadów i nie jest systemem bezpieczeństwa.
wieża
24
@The Rook, może to być trywialna bariera (atakujący może przechwycić klienta użytkownika ofiary za pomocą własnej witryny) i polega na bezpieczeństwie poprzez zaciemnienie, ale nadal jest to jedna dodatkowa bariera. Gdyby HTTP User-Agent zmienił się podczas korzystania z sesji, byłby to wyjątkowo podejrzany i najprawdopodobniej atak. Nigdy nie powiedziałem, że możesz go używać sam. Jeśli połączysz to z innymi technikami, uzyskasz znacznie bezpieczniejszą witrynę.
grom
5
@grom Myślę, że to tak, jakbyś nakrył drzwi kawałkiem taśmy klejącej i powiedział, że zapobiegnie to włamaniom.
wieża
8
Jeśli sprawdzasz agenta użytkownika, blokujesz wszystkie żądania od użytkowników IE8, gdy przełączają tryb zgodności. Zobacz zabawę, jaką miałem, śledząc ten problem we własnym kodzie: serverfault.com/questions/200018/http-302-problem-on-ie7 . Wychodzę z agentem użytkownika, ponieważ fałszowanie jest tak trywialne, jak powiedzieli inni.
obecność
15

Jedną ze wskazówek jest wywołanie session_regenerate_id za każdym razem, gdy zmienia się poziom bezpieczeństwa sesji. Pomaga to zapobiegać przejmowaniu sesji.

saint_groceon
źródło
11

Moje dwa (lub więcej) centów:

Jest mała, ale dobra książka na ten temat: Essential PHP Security autorstwa Chrisa Shifletta .

Niezbędne zabezpieczenia PHP http://shiflett.org/images/essential-php-security-small.png

Na stronie głównej książki znajdziesz kilka interesujących przykładów kodu i przykładowe rozdziały.

Możesz użyć wspomnianej powyżej techniki (IP & UserAgent), opisanej tutaj: Jak uniknąć kradzieży tożsamości

takeshin
źródło
+1 za ochronę przed XSS. Bez tego nie da się zabezpieczyć przed CSRF, a zatem ktoś może „jeździć” na sesji, nawet nie uzyskując identyfikatora sesji.
Kornel
11

Myślę, że jednym z głównych problemów (którym zajmuje się PHP 6) jest register_globals. Teraz jeden ze standardowych metod stosowanych w celu uniknięcia register_globalsjest użycie $_REQUEST, $_GETlub $_POSTtablic.

"Prawidłowym" sposobem na zrobienie tego (od 5.2, chociaż jest tam trochę wadliwy, ale stabilny od 6, co wkrótce się pojawi) są filtry .

Więc zamiast:

$username = $_POST["username"];

ty byś zrobił:

$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);

lub po prostu:

$username = filter_input(INPUT_POST, 'username');
cmcculloh
źródło
2
To w ogóle nie ma związku z pytaniem.
The Pixel Developer
5
Naprawdę? Dlaczego więc w przyjętej odpowiedzi wspominają o nieużywaniu register globals? Czy, tak dalece jak jest to zaniepokojone większością zwykłych programistów, nie rejestrowałby zmiennych globalnych i obsługi zmiennych w formie „sesji”, nawet jeśli nie jest to technicznie część obiektu „sesji”?
cmcculloh
9
Zgadzam się, to nie jest pełną odpowiedzią na pytanie, ale zdecydowanie jest to CZĘŚĆ odpowiedzi na pytanie. Ponownie, to uzupełnia punkt w zaakceptowanej odpowiedzi „Nie używaj register globals”. To mówi, co robić zamiast tego.
cmcculloh
5

Korzystanie z adresu IP nie jest najlepszym pomysłem z mojego doświadczenia. Na przykład; moje biuro ma dwa adresy IP, które są używane w zależności od obciążenia i stale napotykamy problemy z używaniem adresów IP.

Zamiast tego zdecydowałem się na przechowywanie sesji w oddzielnej bazie danych dla domen na moich serwerach. W ten sposób nikt w systemie plików nie ma dostępu do informacji o tej sesji. Było to bardzo pomocne w przypadku phpBB przed 3.0 (od tego czasu naprawili to), ale myślę, że nadal jest to dobry pomysł.

Eric Lamb
źródło
3

Jest to dość trywialne i oczywiste, ale pamiętaj o session_destroy po każdym użyciu. Może to być trudne do zaimplementowania, jeśli użytkownik nie wyloguje się jawnie, więc można ustawić licznik czasu, aby to zrobić.

Oto dobry samouczek dotyczący setTimer () i clearTimer ().

cześć
źródło
3

Główny problem z sesjami PHP i bezpieczeństwem (poza przechwytywaniem sesji) dotyczy środowiska, w którym się znajdujesz. Domyślnie PHP przechowuje dane sesji w pliku w katalogu tymczasowym systemu operacyjnego. Bez specjalnego przemyślenia i planowania jest to katalog, który można odczytać na całym świecie, więc wszystkie informacje o sesji są jawne dla każdego, kto ma dostęp do serwera.

Jeśli chodzi o utrzymywanie sesji na wielu serwerach. W tym momencie byłoby lepiej przełączyć PHP na sesje obsługiwane przez użytkownika, w których wywołuje on dostarczone funkcje do CRUD (tworzenie, odczytywanie, aktualizowanie, usuwanie) danych sesji. W tym momencie możesz przechowywać informacje o sesji w bazie danych lub rozwiązaniu podobnym do memcache, aby wszystkie serwery aplikacji miały dostęp do danych.

Przechowywanie własnych sesji może być również korzystne, jeśli jesteś na serwerze współdzielonym, ponieważ umożliwia przechowywanie ich w bazie danych, nad którą często masz większą kontrolę niż system plików.

John Downey
źródło
3

Skonfigurowałem swoje sesje w ten sposób-

na stronie logowania:

$_SESSION['fingerprint'] = md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR']);

(fraza zdefiniowana na stronie konfiguracyjnej)

następnie w nagłówku znajdującym się w pozostałej części witryny:

session_start();
if ($_SESSION['fingerprint'] != md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR'])) {       
    session_destroy();
    header('Location: http://website login page/');
    exit();     
}
Czad
źródło
3

php.ini

session.cookie_httponly = 1
change session name from default PHPSESSID

eq Apache dodaj nagłówek:

X-XSS-Protection    1
user956584
źródło
httpd.conf -> <FilesMatch "\. (php | phtml | aspx | htm | html) $"> Zestaw nagłówków X-XSS-Protection "1" </FilesMatch>
user956584
Pamiętaj, że X-XSS-Protectionto wcale nie jest przydatne. W rzeczywistości sam algorytm zabezpieczający mógłby zostać wykorzystany, czyniąc go gorszym niż wcześniej.
Pacerier,
2

Sprawdziłbym zarówno adres IP, jak i agenta użytkownika, aby zobaczyć, czy się zmieniają

if ($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']
    || $_SESSION['user_ip'] != $_SERVER['REMOTE_ADDR'])
{
    //Something fishy is going on here?
}
Teifion
źródło
5
Adres IP może się zmienić, jeśli użytkownik znajduje się za farmą proxy ze zrównoważonym obciążeniem.
Kornel
2
User_agent może się zmieniać za każdym razem, gdy użytkownik uaktualnia przeglądarkę.
scotts
3
@scotts Zgadzam się z częścią IP, ale do aktualizacji przeglądarki ustawisz sesję, gdy się logują, więc nie widzę, jak zaktualizowaliby tam przeglądarkę bez tworzenia nowej sesji po ponownym zalogowaniu.
JasonDavis,
Uważam, że user_agent może się również zmienić podczas przełączania między trybem kompatybilności w IE8. Bardzo łatwo jest też sfałszować.
Tak, ale co z użytkownikami, którzy mieli statyczny adres IP eq GSM i jest zmieniany co pół godziny. Tak więc przechowywane IP w Session + nazwa hosta, KIEDY IP! = REMOTE_ADDR sprawdź hosta i porównaj eq. 12.12.12.holand.nl-> kiedy jest holand.nl == true. Ale jakiś host miał nazwę hosta opartą na IP Następnie trzeba porównać maskę 88.99.XX.XX
user956584
2

Jeśli używasz session_set_save_handler () , możesz ustawić własną obsługę sesji. Na przykład możesz przechowywać swoje sesje w bazie danych. Przykłady obsługi sesji bazy danych można znaleźć w komentarzach php.net.

Sesje DB są również dobre, jeśli masz wiele serwerów, w przeciwnym razie, jeśli używasz sesji opartych na plikach, musisz się upewnić, że każdy serwer WWW ma dostęp do tego samego systemu plików, aby odczytywać / zapisywać sesje.

ejunker
źródło
2

Musisz mieć pewność, że dane sesji są bezpieczne. Patrząc na swój php.ini lub używając phpinfo (), możesz znaleźć ustawienia sesji. _session.save_path_ informuje, gdzie są zapisywane.

Sprawdź uprawnienia folderu i jego elementów nadrzędnych. Nie powinien być publiczny (/ tmp) ani być dostępny dla innych witryn internetowych na Twoim współdzielonym serwerze.

Zakładając, że nadal chcesz używać sesji php, możesz ustawić php, aby używał innego folderu, zmieniając _session.save_path_ lub zapisując dane w bazie danych, zmieniając _session.save_handler_.

Możesz ustawić _session.save_path_ w swoim php.ini (niektórzy dostawcy na to pozwalają) lub dla apache + mod_php, w pliku .htaccess w folderze głównym twojej witryny: php_value session.save_path "/home/example.com/html/session" . Możesz również ustawić go w czasie wykonywania za pomocą _session_save_path () _.

Sprawdź samouczek Chrisa Shifletta lub Zend_Session_SaveHandler_DbTable, aby ustawić i alternatywną procedurę obsługi sesji.

Dinoboff
źródło