14

I'm testing the implementation of a security check in my PHP sessions. I can successfuly detect whether the session was started from another IP address and I can successfully start a new session. However, the data from the old session gets copied into the new one! How can I start a blank session while preserving the previous session data for its legitimate owner?

This is my code so far, after lots of failed attempts:

<?php

// Security check
if( isset($_SESSION['ip_address']) && $_SERVER['REMOTE_ADDR']!=$_SESSION['ip_address'] ){
    // Check failed: we'll start a brand new session
    session_regenerate_id(FALSE);
    $tmp = session_id();
    session_write_close();
    unset($_SESSION);
    session_id($tmp);
    session_start();
}

// First time here
if( !isset($_SESSION['ip_address']) ){
    $_SESSION['ip_address'] = $_SERVER['REMOTE_ADDR'];
    $_SESSION['start_date'] = new DateTime;
}

The official documentation about sessions is terribly confusing :(

Update: I'm posting some findings I got through trial and error. They seem to work:

<?php

// Load the session that we will eventually discard
session_start();

// We can only generate a new ID from an open session
session_regenerate_id();

// We store the ID because it gets lost when closing the session
$tmp = session_id();

// Close session (doesn't destroy data: $_SESSION and file remains)
session_destroy();

// Set new ID for the next session
session_id($tmp);
unset($tmp);

// Start session (uses new ID, removes values from $_SESSION and loads the new ones if applicable)
session_start();
Álvaro González
  • 142,137
  • 41
  • 261
  • 360
  • 2
    @Álvaro G. Vicario - session_destroy ?http://php.net/manual/en/function.session-destroy.php or session_unregister - http://www.php.net/manual/en/function.session-unregister.php – ajreal Dec 03 '10 at 11:23
  • @ajreal, you are right: although the name session_destroy() suggests that it removes session data, it doesn't. I'm testing it to find out what it does exactly. Feel free to elaborate this in an answer. – Álvaro González Dec 03 '10 at 11:33
  • session_unregister() is deprecated, BTW. – Álvaro González Dec 03 '10 at 11:55
  • @Álvaro G. Vicario - aiya, 5.3? ...one more, session_unset - http://www.php.net/manual/en/function.session-unset.php – ajreal Dec 03 '10 at 12:15
  • 1
    @ajreal, nope, 5.2; *you* removed the tag one hour ago :) – Álvaro González Dec 03 '10 at 12:27
  • @Álvaro G. Vicario - oh yeah ... i remove that because **php52** does not sound correct ... since is going to discard after 5.3, better avoid that – ajreal Dec 03 '10 at 12:28

4 Answers4

9

Just call session_unset after session_regenerate_id to reset $_SESSION for the current session:

if (isset($_SESSION['ip_address']) && $_SERVER['REMOTE_ADDR']!=$_SESSION['ip_address']) {
    // Check failed: we'll start a brand new session
    session_regenerate_id(FALSE);
    session_unset();
}
Gumbo
  • 643,351
  • 109
  • 780
  • 844
  • 1
    The manual discourages this: *If $_SESSION [...] is used, use unset() to unregister a session variable, i.e. unset ($_SESSION['varname'])* – Álvaro González Dec 03 '10 at 11:49
  • 1
    @Álvaro G. Vicario: It says “[…] use `unset()` to unregister *a* session variable […]” and “Do NOT unset the whole `$_SESSION` with `unset($_SESSION)` […]”. There is nothing said like *‍do not use `session_unset` to reset the whole `$_SESSION`‍*‍‍. – Gumbo Dec 03 '10 at 11:54
  • Just tested: session_unset() removes the session data. I cannot use it inside the first session because I want to keep it but I guess I can use it inside the second one. Sounds illogical but it should work. – Álvaro González Dec 03 '10 at 12:18
  • @Álvaro G. Vicario: `session_regenerate_id` basically creates a new session and copies the session data from the old session to the new session. So calling `session_unset` will only affect the new session and not the old one. – Gumbo Dec 03 '10 at 12:20
  • After this code, you still have to call `session_start()` to start a new session, right? Or is it *actually* reset? – Bram Vanroy Apr 28 '16 at 10:08
2

when a new user connects to your server, the script should only be able to access that user's session variables. you will want to store other info in a hashed session variable to verify that the session is not being jacked. if it is being jacked, no reason to start a new session, maybe just exit the script with a warning.

here is the function a lot of people use for fingerprinting a session:

function fingerprint() {
    $fingerprint = $server_secure_word;
    $fingerprint .= $_SERVER['HTTP_USER_AGENT'];
    $blocks = explode('.', $_SERVER['REMOTE_ADDR']);
    for ($i=0; $i<$ip_blocks; $i++) {
        $fingerprint .= $blocks[$i] . '.';
    }
    return md5($fingerprint);
}
dqhendricks
  • 19,030
  • 11
  • 50
  • 83
1

Use this

unset($_SESSION['ip_address'])

instead of 'unset($_session)' You can also use session_destroy.

Adeel
  • 605
  • 1
  • 6
  • 16
0

session_destroy will destroy session data. For example,

session_start();
$_SESSION["test"] = "test";
session_write_close();
session_start();
// now session is write to the session file
// call session_destroy() will destroy all session data in the file.
session_destroy();
// However the you can still access to $_SESSION here
print_r($_SESSION);
// But once you start the session again
session_start();
// all session data is gone as the session file is now empty
print_r($_SESSION);

will output

array([test] => "test")array()
attempt0
  • 639
  • 5
  • 14
  • I haven't looked into this in several years but, if I recall correctly, the problem with `session_destroy()` was that it would not remove the file (i.e., you could still open a the old session with the old ID). I may test again. – Álvaro González Aug 05 '17 at 08:38