I am learning PHP after using Classic ASP since 2001.
I've come to the point of working out how to secure the admin section of a site I'm working on, and have been reading here:
https://paragonie.com/blog/2015/04/fast-track-safe-and-secure-php-sessions
I've seen that it appears to be bad practice to bind a session to an IP address - e.g.
Check if the
$_SERVER['REMOTE_ADDR']
matches$_SESSION['ip']
As taken from the link above:
Some systems like to bind a session to a particular IP address. This is not generally recommended; Tor users, in particular, will have difficulty staying authenticated. You can enforce this restriction here too.
session_start();
// Make sure we have a canary set
if (!isset($_SESSION['canary'])) {
session_regenerate_id(true);
$_SESSION['canary'] = [
'birth' => time(),
'IP' => $_SERVER['REMOTE_ADDR']
];
}
if ($_SESSION['canary']['IP'] !== $_SERVER['REMOTE_ADDR'])) {
session_regenerate_id(true);
// Delete everything:
foreach (array_keys($_SESSION) as $key) {
unset($_SESSION[$key]);
}
$_SESSION['canary'] = [
'birth' => time(),
'IP' => $_SERVER['REMOTE_ADDR']
];
}
// Regenerate session ID every five minutes:
if ($_SESSION['canary']['birth'] < time() - 300) {
session_regenerate_id(true);
$_SESSION['canary']['birth'] = time();
}
I can't work this one out - is the blog post saying that it is wrong to bind a session to an IP address, and then posting code showing how you can do that?
Or is the "canary" session code they use not actually binding a session to an IP address?
Assuming the code isn't binding a session to an IP address and that it would be good practice to use it, then I'm a bit confused about how I would use this canary session - would I put this bit on my login page, once a user has successfully logged in:
// Make sure we have a canary set
if (!isset($_SESSION['canary'])) {
session_regenerate_id(true);
$_SESSION['canary'] = [
'birth' => time(),
'IP' => $_SERVER['REMOTE_ADDR']
];
}
// set my own session variable as well
if (!isset($_SESSION['name'])) {
$_SESSION['name'] = $name; // $name = value from database
header('Location:admin-home.php');
exit;
}
And then put these bits at the top of any pages which are user protected:
session_start();
// ####################################################################################################
// Is User Logged In?
// ####################################################################################################
$name = $_SESSION['name'];
if (!isset($name)) {
header('Location:login.php');
exit;
}
// ####################################################################################################
// Canary Session?
// https://paragonie.com/blog/2015/04/fast-track-safe-and-secure-php-sessions
// ####################################################################################################
if ($_SESSION['canary']['IP'] !== $_SERVER['REMOTE_ADDR']) {
session_regenerate_id(true);
// Delete everything:
foreach (array_keys($_SESSION) as $key) {
unset($_SESSION[$key]);
}
$_SESSION['canary'] = [
'birth' => time(),
'IP' => $_SERVER['REMOTE_ADDR']
];
}
// Regenerate session ID every five minutes:
if ($_SESSION['canary']['birth'] < time() - 300) {
session_regenerate_id(true);
$_SESSION['canary']['birth'] = time();
}
I will also be using HTTPS for the login and admin pages.
The way PHP handles sessions, is to generate a unique session id for each user, and store it in a cookie (default name PHPSESSID). This works well across IP changes, and gives different session on different browsers on the same machine.
To give more security, you can also save user ip and user agent in session, and check that on every request. I'm not sure whether PHP does this by default or not, but it would be rather simple to implement it.
You can also look for session implementation on famous frameworks (Laravel, Symfony, ...) to see how they do it. I leave it to you to further investigate topic, as it should be a bit of googling and reading source code.