Jak unikalny jest identyfikator sesji php

90

Jak unikalny jest identyfikator sesji php? Odniosłem wrażenie z różnych rzeczy, które przeczytałem, że nie powinienem polegać na tym, że dwóch użytkowników nigdy nie otrzyma tego samego identyfikatora sesji. Czy to nie jest GUID?

Jalov
źródło

Odpowiedzi:

39

Session_id rzeczywiście można zduplikować, ale prawdopodobieństwo jest bardzo niskie. Jeśli masz witrynę o dużym natężeniu ruchu, może się to zdarzyć raz w życiu witryny i po prostu denerwować jednego użytkownika na jedną sesję.

Nie warto się tym przejmować, chyba że spodziewasz się zbudować bardzo ruchliwą stronę internetową lub usługę dla branży bankowej.

e-satis
źródło
4
Słyszałem doniesienia o witrynach, które miały wiele przypadków kolizji.
ColinM
20
Pytanie zostało zadane prawie 4 lata temu. Byłoby interesujące wiedzieć, czy algorytm identyfikatora sesji od tego czasu improwizował ...
Sliq
@ColinM: a witryny te miały 1 milion unikalnych użytkowników dziennie.
e-satis
1
Najprawdopodobniej jest obecnie oparty (hash MD5 / SHA1) na zdalnym adresie użytkownika, czasie lokalnym i pewnej liczbie losowej (LCG) .
Caramiriel,
2
Nie muszę łamać telefonu komórkowego, telefon komórkowy ciągle się psuje. :)
hakre
67

Nie jest bardzo wyjątkowy w dostarczonej postaci. W domyślnej konfiguracji jest to wynik mieszania różnych rzeczy, w tym wyniku gettimeofday (co nie jest strasznie unikalne), ale jeśli się martwisz, powinieneś skonfigurować go tak, aby pobierał jakąś entropię z / dev / urandom, jak tak

ini_set("session.entropy_file", "/dev/urandom");
ini_set("session.entropy_length", "512");

wyszukaj „php_session_create_id” w kodzie używanego algorytmu.

Edytowano, by dodać: istnieje generator liczb losowych DFA zapoczątkowany przez pid, zmieszany z czasem w usek. Nie jest to mocny warunek wyjątkowości, zwłaszcza z punktu widzenia bezpieczeństwa . Użyj powyższej konfiguracji entropii.

Aktualizacja:

Od PHP 5.4.0 session.entropy_file domyślnie / dev / urandom lub / dev / arandom, jeśli jest dostępny. W PHP 5.3.0 ta dyrektywa jest domyślnie pozostawiona pusta. Podręcznik PHP

djsadinoff
źródło
1
Tak, kiedy podpisałem kontrakt na stronę internetową, która musiała być bardzo bezpieczna przeciwko wrogim kombatantom i tym podobnym, stworzyłem własną procedurę obsługi sesji i przekazałem jej dane entropii bezpośrednio z random.org. Ale wymagania tego systemu znacznie wykraczały poza to, z czym radzi sobie większość zwykłych śmiertelników w / ;-)
Theodore R. Smith,
1
@ thomas-jensen, gettimeofday jest uniksowym znacznikiem czasu, z wyjątkiem tego, że jest wyrażony w μsec (czasami). Przeczytaj powyższą metodę php_session_create_id.
djsadinoff
4
Zmiana długości entropii poprawia losowość, ale nie wpływa znacząco na prawdopodobieństwo kolizji, ponieważ hasz ma wciąż tę samą długość. Jednak zmiana session.hash_function pozwala na użycie dłuższych skrótów, takich jak na przykład sha512.
ColinM
2
To dziwne, że zdarzają się kolizje. Z pewnością PHP powinno sprawdzić, czy pod tym identyfikatorem istnieje poprawna sesja, a następnie wygenerować inny identyfikator.
Luke
1
@ theodore-r-smith, naprawdę złą praktyką jest pobieranie entropii z publicznie dostępnego źródła. Powinieneś założyć, że Twoi "Enemy Combatants" również mają dostęp do random.org ...
avri
12

Jeśli chcesz wiedzieć, jak PHP domyślnie generuje identyfikator sesji, sprawdź kod źródłowy na Github . Z pewnością nie jest losowy i opiera się na skrócie (domyślnie: md5) tych składników (zobacz wiersz 310 fragmentu kodu):

  1. Adres IP klienta
  2. Obecny czas
  3. PHP Linear Congruence Generator - generator liczb pseudolosowych (PRNG)
  4. Losowe źródło specyficzne dla systemu operacyjnego - jeśli system operacyjny ma dostępne losowe źródło (np. / Dev / urandom)

Jeśli system operacyjny ma dostępne losowe źródło, wówczas siła wygenerowanego identyfikatora, który ma być identyfikatorem sesji, jest wysoka ( / dev / urandom i inne losowe źródła systemu operacyjnego to (zwykle) zabezpieczone kryptograficznie PRNG ). Jeśli jednak tak się nie stanie, jest to zadowalające.

Celem generowania identyfikacji sesji jest:

  1. zminimalizować prawdopodobieństwo wygenerowania dwóch identyfikatorów sesji o tej samej wartości
  2. sprawiają, że generowanie losowych kluczy i trafianie w używany jest bardzo trudne pod względem obliczeniowym .

Osiąga się to dzięki podejściu PHP do generowania sesji.

Nie można absolutnie zagwarantować wyjątkowości , ale prawdopodobieństwo dwukrotnego trafienia tego samego skrótu jest tak niskie, że ogólnie rzecz biorąc nie warto się tym martwić.

GordyD
źródło
11

Możesz zainstalować alternatywną funkcję generowania skrótu, jeśli chcesz dostosować sposób generowania identyfikatora (jest to domyślnie 128-bitowa liczba generowana przez MD5). Zobacz http://www.php.net/manual/en/session.configuration.php#ini.session.hash-function

Więcej informacji na temat sesji PHP można znaleźć w tym doskonałym artykule http://shiflett.org/articles/the-truth-about-sessions, który zawiera również linki do innych artykułów na temat naprawiania sesji i przechwytywania.

Paul Dixon
źródło
2
Aby być dokładnym, ustaw „session.hash_function = sha512” dla PHP 5.3 i nowszych, aby przejść do 512-bitowego hasha. To powinno załatwić sprawę. W przypadku ustawień domyślnych w witrynach o dużym natężeniu ruchu często występują kolizje.
ColinM
5

Rozmiar session_id
Załóżmy, że seesion_id jest równomiernie rozłożone i ma rozmiar = 128 bitów. Załóżmy, że każda osoba na planecie loguje się raz dziennie z trwałą nową sesją przez 1000 lat.

num_sesion_ids  = 1000*365.25 *7*10**9 < 2**36
collission_prob < 1 - (1-1/2**82)**(2**36)  ≈ 1 - e**-(1/2**46) 
                ≈ 1/2**46 

Zatem prawdopodobieństwo jednej lub więcej kolizji jest mniejsze niż jedna na 70 tysięcy miliardów. Stąd 128-bitowy rozmiar session_id powinien być wystarczająco duży. Jak wspomniano w innych komentarzach, menadżer_sesji może również sprawdzić, czy nowy identyfikator_sesji już nie istnieje.

Losowość
Dlatego myślę, że głównym pytaniem jest to, czy session_id: s są generowane z dobrą pseudolosowością. Tego nigdy nie można być pewnym, ale polecałbym skorzystać z dobrze znanego i często używanego standardowego rozwiązania do tego celu (jak już prawdopodobnie robisz).

Nawet jeśli kolizje są unikane ze względu na sprawdzanie, ważna jest losowość i rozmiar session_id, tak aby hakerzy nie mogli, w jakiś sposób przeprowadzić kwalifikowanego zgadywania i znaleźć aktywne session_id: s z dużym prawdopodobieństwem.

MrJ
źródło
3
Nie jestem matematykiem, ale myślę, że zapominasz o problemie z urodzinami, więc szanse na kolizję, gdy są jeszcze małe, są znacznie większe niż sugerujesz. Ponadto, jak zasugerował djsadinoff, PHP niekoniecznie domyślnie używa dobrej metody generowania liczb losowych.
ColinM
Nie, faktycznie szacunki są aktualne. Powyższe obliczenie jest uproszczonym oszacowaniem, w którym szacujemy, że prawdopodobieństwo kolizji dla session_id nr i wynosi = 1/2 82 (powinno jednak wynosić 1/2 92 powyżej = literówka). W rzeczywistości prawdopodobieństwo wynosi (i-1) / 2 128, o ile nie doszło do wcześniejszych kolizji. 1/2 92 zachowań tylko dla ostatniej sesji session_id.
MrJ
3

Nie znalazłem potwierdzenia tego, ale uważam, że php sprawdza, czy identyfikator sesji już istnieje, zanim utworzy go z tym identyfikatorem.

Problem przechwytywania sesji, o który ludzie się martwią, występuje, gdy ktoś poznaje identyfikator sesji aktywnego użytkownika. Można temu zapobiec na wiele sposobów, więcej informacji na ten temat można znaleźć na tej stronie php.net oraz w tym artykule o utrwalaniu sesji

Ólafur Waage
źródło
2
... ale jeśli jesteś tylko jednym serwerem php w banku składającym się z kilku, nie ma gwarancji, że serwer ma wystarczającą wiedzę, aby wiedzieć, czy identyfikator sesssionID był już używany.
djsadinoff
Dlaczego miałoby to mieć znaczenie, jeśli mam ten sam identyfikator sesji na 2 różnych serwerach php? Zakładając 2 różne domeny, plik cookie sesji jest dostępny tylko z każdej domeny ...?
daremon
3
Najłatwiejszym sposobem uniknięcia duplikatów w środowisku wieloserwerowym jest przechowywanie sesji w memcached za pośrednictwem modułu obsługi sesji memcached. problem został rozwiązany, a Twoi użytkownicy mogą odbijać się od serwerów diff bez utraty swoich rzeczy.
Theodore R. Smith
@daremon mówi o wielu serwerach dla jednej domeny.
gtd
To jest po prostu niepoprawne. PHP nie sprawdza istniejących identyfikatorów sesji podczas generowania nowych. Spójrz na dowolny kod obsługi sesji PHP i po prostu nie ma metody zaimplementowanej w tym celu.
ColinM
2

Nie, identyfikator sesji nie jest identyfikatorem GUID, ale dwóch użytkowników nie powinno otrzymać tego samego identyfikatora sesji, który jest przechowywany po stronie serwera.

gadżet
źródło
2
Możliwe, że pamięć po stronie serwera w żaden sposób nie gwarantuje wyjątkowości. Wyjątkowość to jedno - jeśli wystąpi kolizja, zderzy się niezależnie od tego, gdzie jest przechowywana sesja.
Nie przeze mnie, doceniam twoją odpowiedź (podobnie jak inni). - Jalov
Jalov
2
Identyfikatory sesji są przechowywane zarówno po stronie serwera, jak i klienta. Zawartość sesji jest przechowywana po stronie serwera. Fakt ten prawie nie jest związany z niepowtarzalnością identyfikatora sesji.
YudhiWidyatama,
0

Możesz zdecydować się na przechowywanie różnych sesji w DB wraz z unikalnym polem generującym DB; połącz je i zapisz w zmiennej sesji, a następnie sprawdź tę zamiast identyfikatora sesji.

Zgubny
źródło
Witamy w stackoverflow. Twoja odpowiedź nie jest niestety próbą odpowiedzi na pytanie. OP zapytał, jak unikalny jest identyfikator sesji. Przechowywanie danych w bazie danych, a następnie używanie zmiennej sesji w celu ich pobrania tylko zwiększa złożoność problemu, prawda?
Noah Boegli
@NoahBoegli inne rozwiązania zasugerowały o wiele bardziej skomplikowaną metodę.
Zgubny
-4
<?php
session_start();
$_SESSION['username']="username";
?>

<!DOCTYPE html>
<html>
<head>
    <title>Update</title>
</head>
<body>

<table border="2">
    <tr>
        <th>Username</th>
        <th>Email</th>
        <th>Edit</th>
    </tr>
<?php
     $conn=mysqli_connect("localhost","root","","telephasic");
     $q2="select * from register where username = '".$_SESSION['username']."'";
     $run=mysqli_query($conn, $q2);
     while($row=mysqli_fetch_array($run))
     {
         $name=$row[1];
         $email=$row[2];
     ?>

    <tr>
        <td><?php echo $name; ?></td>
        <td><?php echo $email; ?></td>
        <td><a href="edit.php"> Edit </a></td>
    </tr>
 <?php } ?>
 </table> 
 </body>

jeśli Twoja nazwa użytkownika jest inna lub niepowtarzalna, możesz użyć tego kodu do sesji

Arun Sharma
źródło