<?php
/**
* Perform security checks on the session requests
* You may want to fine tune the network validation routines here
* e.g. being more specific for LAN traffic, less for mobile
*/
/**
* note that we need to store data inside the session, and that means we need
* to use a serialization method accessible from the PHP code
* and *that* means we need at least v5.5.4
*/
if (version_compare(PHP_VERSION, '5.5.4') >=0) {
ini_set('session.serialize_handler', 'php_serialize');
} else {
trigger_error("Security session handler requires PHP 5.5.4 or later", E_USER_ERROR);
}
class securitySession extends stackSess {
function open($save_path, $name)
{
if ($this->shStackNext) {
return $this->shStackNext->open($save_path, $name);
} else {
trigger_error("Security session handler has no storage capability", E_USER_ERROR);
return false;
}
}
function read($session_id)
{
// we don't allow an expired session to be read
if ($this->shStackNext) {
$session_str=$this->shStackNext->read($session_id);
// above required to populate lastAccess...
$lastAccess=$this->shStackNext->lastAccessed();
$max_ttl=ini_get('session.cookie_lifetime');
if ($max_ttl && time()-$lastAccess>$lastAccess) {
$this->logit("Session accessed after expiry", E_USER_NOTICE);
$this->destroy($session_id);
return '';
}
$session_sr=$this->securityCheck($session_id, $session_str);
return $session_str;
}
return false;
}
function create_sid($newlyCreatedSid=false)
{
if (is_callable(array($this->shStackNext,'create_sid'))) {
// we always send down the stack
$newlyCreatedSid=$this->shStackNext->create_sid($newlyCreatedSid);
}
return $newlyCreatedSid;
}
function securityCheck($session_id, $session_str)
{
$sess=unserialize($session_str);
if (!isset($sess['securityCheck'])) {
// data is not yet populated - populate now
$sess['securityCheck']=array(
'user_agent'=>$_SERVER['HTTP_USER_AGENT'],
'c_ip'=>$_SERVER["REMOTE_ADDR"]
);
return serialize($sess);
}
$stored_ua=get_browser($sess['securityCheck']['user_agent'], true);
$current_ua=get_browser(null, true);
if ($stored_ua['platform'] != $current_ua['platform']
|| $stored_ua['parent'] != $current_ua['parent']) {
$this->logit("Details changed mid session " . var_export($sess['securityCheck'],true), E_USER_NOTICE);
return false;
}
if (!$this->compareIP($sess['securityCheck']['c_ip'], $_SERVER["REMOTE_ADDR"])) {
$this->logit("Client network changed from $sess[securityCheck][c_ip]", E_USER_NOTICE);
return false;
}
return $session_str;
}
// if you don't get an exact match, you might want to
// compare netmasks, or the Organisation in the whois, or the ASN
function compareIP($ip1, $ip2)
{
if ($ip1==$ip2 || !$ip1 || !$ip2) {
return true;
}
}
}
|