Skip to content

Instantly share code, notes, and snippets.

@pete-webpagetech
Forked from eddmann/SecureSessionHandler.php
Last active July 16, 2016 23:07
Show Gist options
  • Save pete-webpagetech/49bfd623c6821528754c to your computer and use it in GitHub Desktop.
Save pete-webpagetech/49bfd623c6821528754c to your computer and use it in GitHub Desktop.
PHP Encrypted Session save Handler with session access class
<?php
/*
*
* Session class fork from eddmann/SecureSessionHandler.php
* SecureSession fork from ezimuel/PHP-Secure-Session
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
/**
* show off @property, @property-read, @property-write
* @property mixed $* maps to $_SESSION[*] Set/Get/isset/unset session varibles though Magic Methods
* @property-read mixed $* maps to $_SESSION[*]
* @property-write mixed $* maps to $_SESSION[*]
*/
class Session extends SecureSession {
protected $_use_ip=FALSE;
public function __construct($useIp=FALSE){
if($useIp==TRUE){
$this->_use_ip=TRUE;
}
parent::__construct();
}
public function start(){
if(session_status() == PHP_SESSION_NONE){
if (session_start()) {
return mt_rand(0, 4) === 0 ? $this->refresh() : true; // 1/5
}
}
return false;
}
public function refresh(){
return session_regenerate_id(true);
}
public function forget(){
if (session_status() == PHP_SESSION_NONE) {
return false;
}
return session_destroy();
}
public function isValid(){
return ! $this->isExpired() && $this->isFingerprint();
}
private function isExpired($ttl = 30){
$last = isset($_SESSION['_last_activity'])? $_SESSION['_last_activity'] : false;
if ($last !== false && time() - $last > $ttl * 60) {
return true;
}
$_SESSION['_last_activity'] = time();
return false;
}
private function isFingerprint(){
$remoteAddress=($this->_use_ip) ? $_SERVER['REMOTE_ADDR'] : FALSE ;
$hash = md5(
$_SERVER['HTTP_USER_AGENT'] .
(inet_ntop(inet_pton($remoteAddress)) & inet_ntop(inet_pton('255.255.0.0')))
);
if (isset($_SESSION['_fingerprint'])) {
return $_SESSION['_fingerprint'] === $hash;
}
$_SESSION['_fingerprint'] = $hash;
return true;
}
private function filterVar($value){
$val=FALSE;
if(is_string($value)){
$val=filter_var($value, FILTER_SANITIZE_STRING);
}
elseif(is_int($value)){
$val=filter_var($value, FILTER_SANITIZE_NUMBER_INT);
}
elseif(is_float($value)){
$val=filter_var($value, FILTER_SANITIZE_NUMBER_FLOAT);
}
elseif(is_bool($value)){
$val=filter_var($value, FILTER_SANITIZE_STRING);
}
if($val!=FALSE){
return $val;
}else{
return FALSE;
}
}
public function __set($name, $value) {
$paramName=(is_string($name))? filter_var($name,FILTER_SANITIZE_STRING): FALSE;
$paramValue=$this->filterVar($value);
if($paramName!=FALSE){
$_SESSION["$paramName"]=$paramValue;
return TRUE;
}
return FALSE;
}
public function __get($name) {
$paramName=(is_string($name))? filter_var($name,FILTER_SANITIZE_STRING): FALSE;
if($paramName!=FALSE){
if(isset($_SESSION[$paramName])){
return $_SESSION[$paramName];
}
}
return FALSE;
}
public function __isset($name) {
$paramName=(is_string($name))? filter_var($name,FILTER_SANITIZE_STRING): FALSE;
if($paramName!=FALSE){
return isset($_SESSION[$paramName]);
}
return FALSE;
}
public function __unset($name) {
$paramName=(is_string($name))? filter_var($name,FILTER_SANITIZE_STRING): FALSE;
if($paramName!=FALSE){
if(isset($_SESSION[$paramName])){
unset($_SESSION[$paramName]);
return TRUE;
}
}
return FALSE;
}
}
/**
* ------------------------------------------------
* Encrypt PHP session data using files
* ------------------------------------------------
* The encryption is built using mcrypt extension
* and the randomness is managed by openssl
* The default encryption algorithm is AES (Rijndael-128)
* and we use CBC+HMAC (Encrypt-then-mac) with SHA-256
*
* @author Enrico Zimuel (enrico@zimuel.it)
* @copyright GNU General Public License
*/
class SecureSession {
/**
* Encryption algorithm
*
* @var string
*/
protected $_algo= MCRYPT_RIJNDAEL_128;
/**
* Key for encryption/decryption
*
* @var string
*/
protected $_key;
/**
* Key for HMAC authentication
*
* @var string
*/
protected $_auth;
/**
* Path of the session file
*
* @var string
*/
protected $_path;
/**
* Session name (optional)
*
* @var string
*/
protected $_name;
/**
* Size of the IV vector for encryption
*
* @var integer
*/
protected $_ivSize;
/**
* Cookie variable name of the encryption + auth key
*
* @var string
*/
protected $_keyName;
/**
* Generate a random key using openssl
* fallback to mcrypt_create_iv
*
* @param integer $length
* @return string
*/
protected function _randomKey($length=32) {
if(function_exists('openssl_random_pseudo_bytes')) {
$rnd = openssl_random_pseudo_bytes($length, $strong);
if ($strong === true) {
return $rnd;
}
}
return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
}
/**
* Constructor
*/
public function __construct()
{
session_set_save_handler(
array($this, "open"),
array($this, "close"),
array($this, "read"),
array($this, "write"),
array($this, "destroy"),
array($this, "gc")
);
if (!extension_loaded('mcrypt')) {
throw new Exception("The SecureSession class needs the Mcrypt PHP extension, please install it.");
}
$sessionPath = sys_get_temp_dir();
session_save_path($sessionPath);
ini_set('session.gc_probability', 1);
}
/**
* Open the session
*
* @param string $save_path
* @param string $session_name
* @return bool
*/
public function open($save_path, $session_name)
{
$this->_path = $save_path.'/';
$this->_name = $session_name;
$this->_keyName = "KEY_$session_name";
$this->_ivSize = mcrypt_get_iv_size($this->_algo, MCRYPT_MODE_CBC);
if (empty($_COOKIE[$this->_keyName]) || strpos($_COOKIE[$this->_keyName],':')===false) {
$keyLength = mcrypt_get_key_size($this->_algo, MCRYPT_MODE_CBC);
$this->_key = self::_randomKey($keyLength);
$this->_auth = self::_randomKey(32);
$cookie_param = session_get_cookie_params();
setcookie(
$this->_keyName,
base64_encode($this->_key) . ':' . base64_encode($this->_auth),
// if session cookie lifetime > 0 then add to current time; otherwise leave it as zero, honoring zero's special meaning: expire at browser close.
($cookie_param['lifetime'] > 0) ? time() + $cookie_param['lifetime'] : 0,
$cookie_param['path'],
$cookie_param['domain'],
$cookie_param['secure'],
$cookie_param['httponly']
);
} else {
list ($this->_key, $this->_auth) = explode (':',$_COOKIE[$this->_keyName]);
$this->_key = base64_decode($this->_key);
$this->_auth = base64_decode($this->_auth);
}
return true;
}
/**
* Close the session
*
* @return bool
*/
public function close()
{
return true;
}
/**
* Read and decrypt the session
*
* @param integer $id
* @return string
*/
public function read($id)
{
$sess_file = $this->_path.$this->_name."_$id";
if (!file_exists($sess_file)) {
return false;
}
$data = file_get_contents($sess_file);
list($hmac, $iv, $encrypted)= explode(':',$data);
$iv = base64_decode($iv);
$encrypted = base64_decode($encrypted);
$newHmac = hash_hmac('sha256', $iv . $this->_algo . $encrypted, $this->_auth);
if ($hmac !== $newHmac) {
return false;
}
$decrypt = mcrypt_decrypt(
$this->_algo,
$this->_key,
$encrypted,
MCRYPT_MODE_CBC,
$iv
);
return rtrim($decrypt, "\0");
}
/**
* Encrypt and write the session
*
* @param integer $id
* @param string $data
* @return bool
*/
public function write($id, $data)
{
$sess_file = $this->_path . $this->_name . "_$id";
$iv = mcrypt_create_iv($this->_ivSize, MCRYPT_DEV_URANDOM);
$encrypted = mcrypt_encrypt(
$this->_algo,
$this->_key,
$data,
MCRYPT_MODE_CBC,
$iv
);
$hmac = hash_hmac('sha256', $iv . $this->_algo . $encrypted, $this->_auth);
$bytes = file_put_contents($sess_file, $hmac . ':' . base64_encode($iv) . ':' . base64_encode($encrypted));
return ($bytes !== false);
}
/**
* Destoroy the session
*
* @param int $id
* @return bool
*/
public function destroy($id)
{
$sess_file = $this->_path . $this->_name . "_$id";
setcookie ($this->_keyName, '', time() - 3600);
return(@unlink($sess_file));
}
/**
* Garbage Collector
*
* @param int $max
* @return bool
*/
public function gc($max)
{
foreach (glob($this->_path . $this->_name . '_*') as $filename) {
if (filemtime($filename) + $max < time()) {
@unlink($filename);
}
}
return true;
}
}
/*
* Usage...
*/
//start the session
$session = new Session();
$session->start();
//check if current session is expired (30Min default).
if ( ! $session->isValid()) {
$session->forget();
}
//make new session var... uses set magic method
$session->foo="Hello World";
//get an already set session var... uses get magic method
echo $session->foo;
//check if session var is set already... uses isset magic method
if(isset($session->foo)){
//remove an already set session var... uses unset magic method
unset($session->foo);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment