How to generate a unique session ID in php-ThrowExceptions

Exception or error:

On our websites we want to make it possible to share sessions accros multiple domains. All these websites are on the same server but some of them have a different IP address.

The possible solution I found was to set the session ID myself:

<?php
session_id($someUniqueHash);
?>

And this works, if I make the hash like md5(‘test’). On a other domain on te same server we have the session again.

The problem is generating the ID. I see some solutions on the internet with microtime etc, but when I use that approach I can’t predict the session ID on the other domain / PHP page.

Does anyone have an idea? Or shouldn’t we implement this? Are there other options to share session over multiple domains? (NOT subdomains!)

How to solve:

I’ve achieved this system by using an OAuth type flow but we replaced the Consumer with the User.

So each domain would have the authenticated Access_Token in its own session.
You would then use that Access_Token to get information about user from an api.

I also solved the session problem using session_set_save_handler and storing sessions in a database table… This table would have the Access_Token also, making it really easy to find the session with a DB Query.

Hope this helps with ideas.

Answer:

Hmm this is a difficult one.

As everyone knows PHP uses cookies to understand session_ids when a user comes back to your site and there is no way of cross domain cookies: Cross domain cookies (edit: there is but the method is complicated).

This is probably why I have never seen a site implement this even though they have different domains.

You could, via a link on your page from one domain pass the session id to the next domain through $_GET or $_POST. This will not work if the user directly enters your other site.

The only partially (no reliable) method I can come up with is to keep a record of the users comptuer in the DB and use that to understand what session is attached it to. So you house the computers IP address and maybe some other details and that backs onto a session.

The IP and other details of a persons computer would log them into the other domain.

Answer:

Maybe this is not an option for you, but you could try this.

On your main site you generate the session id as per normal and to perpetuate the session to another domain you could include image tags with the session id in the URL. In response, the other domain will set a cookie, so that when the visitor comes there it will already know the session id.

Feels a bit smarty pants solution, but it should work if you don’t have too many other domains 🙂 third party cookies can be disabled separately in browsers btw, something to consider.

Oh btw, session adoption (accepting an id via query parameters and setting a cookie) is delicate stuff and should be protected, i.e. session must already exist before setting cookie.

Answer:

Configure each site individually:

<?php

$cfgsession['file'] = "../sessions_global.txt";
$cfgsession['keepalive'] = 7200;

?>

To make multiple sites share sessions, let them use the same $cfgsession['file'].
Include a session from one site in a request to another domain (perhaps as recommended by Jack), and as long as you don’t catch them making their request in another browser or whatever (please do something to inhibit session hijacking), let them specify a session with $_GET. For example:

include ("../session.php");
if (isset($_COOKIE['session'])) session_begin($_COOKIE['session'], $_SERVER['HTTP_USER_AGENT'] . "+" . $_SERVER['HTTP_ACCEPT_CHARSET'], $_SERVER['REMOTE_ADDR']);
else session_begin("", $_SERVER['HTTP_USER_AGENT'] . "+" . $_SERVER['HTTP_ACCEPT_CHARSET'], $_SERVER['REMOTE_ADDR']);
setcookie("session", session_identity(), 0);

And then just roll your own session_ functions:

<?php

function session_begin($mysession = "", $key = "", $client = "") {
  global $cfgsession;
  if (!preg_match("/^[a-z0-9]{32}$/i", $mysession)) $mysession = md5(microtime());
  $error = false;
  $client = trim($client);
  $key = trim($key);
  $cfgsession['returning'] = false;
  if ($chandle = @tmpfile()) {
    if ($shandle = @fopen($cfgsession['file'], "rb")) {
      flock($shandle, LOCK_SH);
      fputs($chandle, $mysession . " " . time() . " $" . $client . " $" . $key . "\n");
      while (!feof($shandle)) {
        $sline = explode(" ", trim(fgets($shandle)), 4);
        if ($sline[1] >= (time() - $cfgsession['keepalive'])) {
          if (($sline[0] == $mysession) && ($sline[3] == "$" . $key)) {
            $cfgsession['client'] = substr($sline[2], 1);
            $cfgsession['returning'] = true;
          } elseif (count($sline) > 2) fputs($chandle, implode(" ", $sline) . "\n");
        }
      }
      fclose($shandle);
      fseek($chandle, 0);
      if ($shandle = @fopen($cfgsession['file'], "cb")) {
        if (flock($shandle, LOCK_EX)) {
          ftruncate($shandle, 0);
          $cfgsession['count'] = 0;
          while (!feof($chandle)) {
            $cline = trim(fgets($chandle));
            fputs($shandle, $cline . "\n");
            $cfgsession['count']++;
          }
        } else $error = true;
        fclose($shandle);
      } else $error = true;
    } else $error = true;
    fclose($chandle);
  } else $error = true;
  if (($cfgsession['returning'] == false) && ($mysession == $cfgsession['session'])) {
    $cfgsession['returning'] = true;
    $mysession = md5(microtime());
  }
  $cfgsession['session'] = $mysession;

  if ($error) return -1;
  else return 0;
}

function session_count() {
  global $cfgsession;
  return $cfgsession['count'];
}

function session_client() {
  global $cfgsession;
  return $cfgsession['client'];
}

function session_id() {
  global $cfgsession;
  return $cfgsession['session'];
}

function session_index() {
  global $cfgsession;
  $index_return = array();
  if ($uhandle = @fopen($cfgsession['file'], "rb")) {
    flock($uhandle, LOCK_SH);
    while (!feof($uhandle)) {
      $uline = explode(" ", trim(fgets($uhandle)), 4);
      foreach ($uline as &$value) {
        if ($value[0] == "$") $value = substr($value, 1);
      }
      if (count($uline) >= 2) $index_return[] = $uline;
    }
    fclose($uhandle);
  }
  return $index_return;
}

function session_returning() {
  global $cfgsession;
  return $cfgsession['returning'];
}

?>

Answer:

If these are login sessions, consider using a single sign on (SSO) solution such as those that implement the SAML standard.

Leave a Reply

Your email address will not be published. Required fields are marked *