92

How unique is the php session id? I got the impression from various things that I've read that I should not rely on two users never getting the same sessionid. Isn't it a GUID?

Jalov
  • 923
  • 1
  • 7
  • 5

10 Answers10

67

It's not very unique as shipped. In the default configuration it's the result of a hash of various things including the result of gettimeofday (which isn't terribly unique), but if you're worried, you should configure it to draw some entropy from /dev/urandom, like so

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

search for "php_session_create_id" in the code for the actual algorithm they're using.

Edited to add: There's a DFA random-number generator seeded by the pid, mixed with the time in usecs. It's not a firm uniqueness condition especially from a security perspective. Use the entropy config above.

Update:

As of PHP 5.4.0 session.entropy_file defaults to /dev/urandom or /dev/arandom if it is available. In PHP 5.3.0 this directive is left empty by default. PHP Manual

Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
djsadinoff
  • 5,519
  • 6
  • 33
  • 40
  • 1
    Yeah, when I was a contract for a website that had to be ultrasecure against enemy combatants and such, I actually created my own session handler and fed it entropy data directly from random.org. But the reqs of that system were far beyond what most mere mortals deal w/ ;-) – Theodore R. Smith Sep 03 '10 at 01:30
  • I think an entropy length is 512(the max) is not necessary. PHP's config has an option for 16. Default is actually 0. 16 is the highest length I would recommend for any application that doesnt involve highly sensitive information – stan Jan 26 '11 at 18:44
  • Why don't they use UNIX timestamp in the hash? That should eliminate dupes? – Thomas Jensen Jul 18 '11 at 13:37
  • 1
    @thomas-jensen, gettimeofday *is* the unix timestamp, except it's expressed in μsec (sometimes). Read the php_session_create_id method linked above. – djsadinoff Jul 20 '11 at 07:23
  • 4
    Changing the entropy length improves the randomness but does not significantly affect the likelihood of a collision since the hash is still the same length. However, changing session.hash_function allows you to use longer hashes like sha512 for example. – ColinM May 03 '12 at 04:08
  • 3
    I find it bizarre that there are collisions. Surely PHP should be made to check if there is a valid session under that id and subsequently generate a different ID.. – Luke Mar 27 '13 at 14:25
  • 1
    @theodore-r-smith, it is really bad practice to take entropy from a publicly available source. You should assume your "Enemy combatants" also have access to random.org... – avri Oct 26 '15 at 10:40
43

Session_id can indeed be duplicated, but the probability is very low. If you have a website with a fair traffic, it may happens once in you web site life, and will just annoy one user for one session.

This is not worth to care about unless you expect to build a very high traffic website or a service for the bank industry.

Bite code
  • 578,959
  • 113
  • 301
  • 329
  • 4
    I have heard reports of sites that have had many cases of collisions. – ColinM May 03 '12 at 04:17
  • 22
    The question has been asked nearly 4 years ago. It would be interesting to know if the session id algorithm has improvised since then... – Sliq Jun 20 '12 at 12:21
  • @ColinM: and those sites had 1 millions unique visitor / day. – Bite code Jun 22 '12 at 16:19
  • 1
    [Aparantly](https://github.com/php/php-src/blob/a666285bc2488b7f7362368c388e41428610ad1d/ext/session/session.c#L305) its currently based (MD5/SHA1 hash) on the user's remote address, local time and some [random number (LCG)](https://github.com/php/php-src/blob/a666285bc2488b7f7362368c388e41428610ad1d/ext/standard/lcg.c#L55). – Caramiriel Jul 03 '13 at 12:55
  • Even if the chance for a collisions is small, is there no way to check for such collisions and by this avoid them? – humanityANDpeace Oct 30 '13 at 09:57
  • @humanityANDpeace: Use session meta-data to keep track of last activity and remote address/user-agent. If it changes, require to re-login. Get more details and inspiration with a good session security discussion in literature. OWASP checklists often can't hurt as well. – hakre May 18 '14 at 12:28
  • @hakre Congrats, you just broke mobile (Remote IPs change all the time) – Steve Tauber Jul 11 '14 at 12:57
  • 3
    I don't need to break mobile, mobile constantly breaks itself. :) – hakre Jul 11 '14 at 13:13
13

If you want to know how PHP generates a session ID by default check out the source code on Github. It is certainly not random and is based on a hash (default: md5) of these ingredients (see line 273-330 of code snippet):

  1. Cryptographically secure pseudorandom number generator CPRNG

If the OS has a random source available then strength of the generated ID for the purpose of being a session ID is high (/dev/urandom and other OS random sources are (usually) cryptographically secure PRNGs). If however it does not then it is satisfactory.

The goal with session identification generation is to:

  1. minimise the probability of generating two session IDs with the same value
  2. make it very challenging computationally to generate random keys and hit an in use one.

This is achieved by PHP's approach to session generation.

You cannot absolutely guarantee uniqueness, but the probabilities are so low of hitting the same hash twice that it is, generally speaking, not worth worrying about.

Le Duong
  • 3
  • 4
GordyD
  • 5,063
  • 25
  • 29
11

You can install an alternative hash generation function if you want to customise the way the ID is generated (it's a 128bit number generated via MD5 by default). See http://www.php.net/manual/en/session.configuration.php#ini.session.hash-function

For more information on PHP sessions, try this excellent article http://shiflett.org/articles/the-truth-about-sessions which also links to other articles about session fixation and hijack.

NullUserException
  • 83,810
  • 28
  • 209
  • 234
Paul Dixon
  • 295,876
  • 54
  • 310
  • 348
  • 2
    To be exact, set "session.hash_function = sha512" for PHP 5.3 and up to go to 512bit hash. This should do the trick. With the defaults, it IS common on high-traffic sites to get collisions. – ColinM May 03 '12 at 04:05
6

Size of session_id
Assume that seesion_id is uniformly distributed and has size=128 bits. Assume that every person on the planet logs in once a day with a persistent an new session for 1000 years.

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 

So the the probability of one or more collision is less than one in 70 thousand billions. Hence the a 128-bit-size of the session_id should be big enough. As mentioned in other comments, the session_manager might also check that new session_id does not already exist.

Randomness
Therefore the big question I think is whether the session_id:s are generated with good pseudo randomness. On that you can never be sure, but I would recommend using a well known, and frequently used standard solution for this purpose (as you probably already do).

Even if collisions are avoided due to checking, randomness and size of session_id is important, so that hackers can not, somehow do qualified guessing and find active session_id:s with large probability.

MrJ
  • 1,436
  • 2
  • 15
  • 21
  • 3
    I'm no mathematician, but I think you're forgetting the [Birthday problem](http://en.wikipedia.org/wiki/Birthday_problem) so the chances of collision while still small are much greater than you suggest. Also, as djsadinoff suggested, PHP's doesn't necessarily use a good method of generating random numbers by default. – ColinM Aug 02 '12 at 15:41
  • No actually the estimate holds. The above calculation is a simplified estimate, where we estimate that the probability for a collision for session_id nr i, is = 1/2**82 (it should be 1/2**92 above though =typo). In reality the probablility is (i-1)/2**128 as long as no previous collisions has occured. 1/2**92 holds only for the last session_id. – MrJ Sep 03 '12 at 15:54
3

I have not found a confirmation on this but i believe php checks if a session id already exists before creating one with that id.

The session hijacking issue people are worried about is when someone finds out the session id of an active user. This can be prevented in many ways, for more info on that you can see this page on php.net and this paper on session fixation

Ólafur Waage
  • 68,817
  • 22
  • 142
  • 198
  • 2
    ...but if you're just one php server in a bank of several, there's no guarantee that the server has sufficient knowledge to know whether the sesssionID has been used yet. – djsadinoff Sep 26 '08 at 11:03
  • Why would it matter if I got the same session id in 2 different php servers? Assuming 2 different domains, the session cookie is only accessible from each domain...? – daremon Sep 26 '08 at 11:13
  • 3
    The easiest way to prevent dupes on a multi-server environment is to store the sessions in memcached via the memcached session handler. problem solved and your users can bounce around diff servers w/o losing their stuff. – Theodore R. Smith Sep 03 '10 at 01:32
  • @daremon he's talking about multiple servers for one domain. – gtd Mar 02 '11 at 04:37
  • This is simply incorrect. PHP does not check for existing session ids when generating new ones. Look at any PHP session handler code and there is simply no method implemented for this purpose. – ColinM Aug 02 '12 at 15:34
  • @ColinM you are correct. Function php_session_create_id here http://git.php.net/?p=php-src.git;a=blob;f=ext/session/session.c;h=0c08d496816cf92a36b66fbcbafb0d4be3286232;hb=HEAD – Ólafur Waage Aug 02 '12 at 23:38
2

No, session id is not a GUID, but two users should not get the same session id as they are stored on the server side.

gizmo
  • 11,819
  • 6
  • 44
  • 61
  • 2
    Possibly because the server-side storage doesn't guarantee uniqueness in any way. Uniqueness is one thing - if there is a collision it will collide regardless of where the session is stored. –  Sep 26 '08 at 11:29
  • Not by me, I appreciate your response (as well as the others). -- Jalov – Jalov Sep 26 '08 at 11:32
  • 2
    The session ID are stored both in server and client side. The session contents are stored in the server side. And the fact is pretty much not related to uniqueness of the session id. – YudhiWidyatama Mar 24 '13 at 00:02
0

You could opt to store the various session on the DB along with a a DB generate unique field; merge the two and save it in a session variable, then check that one instead the session id.

Pernicious
  • 11
  • 4
  • Welcome to stackoverflow. Your answer does not attempt to answer the question unfortunately. The OP asked how unique the session ID was. Storing the data on the database and then use a session variable to retrieve it only adds more complexity to the problem doesn't it ? – Noah Boegli Sep 23 '20 at 10:48
  • @NoahBoegli other solutions suggested way more complicated method. – Pernicious Sep 23 '20 at 10:58
0

I know this post is very old . Yet, I am adding my answer here since I couldn't find a pertinent solution to this question, Even after posting a similar question myself. I however got a clue from a reply to my post. For those who are interested the algorithm and solution is explained here. It uses a combination of session and a different cookie.

The algorithm in brief is like this

session handling will be done with custom class 'MySessionHandler' using DB

1.just prior to session_start, a cookie cookie_start_time is set to current time. life time of this cookie will be same as that of session. Both uses the variable $this->cookieLifeTime to set life time.

  1. in session ‘_write’ we will set that value to db table field cookie_start_time same as $this->cookieStartTime

  2. in session ‘_read’ we do a check

if($getRowsOfSession[0]['cookie_start_time'] != $this->cookieStartTime).

if it returns true, that means this is a duplicate session and the user is redirected to destroy the session and again redirected to start a new session.(2 redirections total)

-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>

if your username is different or unique you can use this code for session