<?php
/* This file is really *free* software, not like FSF ones.
* Do what you want with this piece of code, I just enjoyed coding, don't care.
*/
/**
* Provides a way to prevent Session Hijacking attacks, using session tokens.
*
* This class was written starting from Claudio Guarnieri's {@link http://www.playhack.net Seride}. I took Claudio's code and learned how it works; then I wrote my own code tring to improve his.
* @author Francesco Ciracì <hide@address.com>
* @link http://sydarex.org
* @version 0.2
* @copyright Copyleft (c) 2009/2010 Francesco Ciracì
*/
/**
* Token class.
*
* Provides a way to prevent Session Hijacking attacks, using session tokens.
*
* This class was written starting from Claudio Guarnieri's {@link http://www.playhack.net Seride}. I took Claudio's code and learned how it works; then I wrote my own code tring to improve his.
*
* @author Francesco Ciracì <hide@address.com>
* @copyright Copyleft (c) 2009, Francesco Ciracì
*/
class Token {
/**
* Stores the question ID.
*
* @access private
* @var integer
*/
private $timeout;
/**
* Stores the new token.
*
* @access private
* @var string
*/
private $token = null;
/**
* Stores the error code raised by Check method.
*
* The possible values are:
* 0 No error detected.
* 1 No Request Token detected.
* 2 No Session Token corrisponding to the Request Token.
* 3 No value for the Session Token.
* 4 Token reached the timeout.
* @access private
* @var integer
*/
private $error = 0;
/**
* Class constructor. Sets class vars, and starts the session if it isn't started yet. Generates the new token.
*
* @param integer $timeout token timeout period, in minutes. Default 5 minutes.
*/
function __construct($timeout=5) {
$this->timeout = $timeout;
if(!isset($_SESSION)) session_start();
$this->tokenSet();
}
/**
* Generates tokens. Generation tecnique taken from {@link http://www.playhack.net Seride}.
*
* @access private
*/
private function tokenGen() {
// Hashes a randomized UniqId.
$hash = sha1(uniqid(rand(), true));
// Selects a random number between 1 and 32 (40-8)
$n = rand(1, 32);
// Generate the token retrieving a part of the hash starting from the random N number with 8 of lenght
$token = substr($hash, $n, 8);
return $token;
}
/**
* Destroys token.
*
* @param string $token the token to destroy.
*/
function tokenDel($token) {
unset($_SESSION[$token]);
}
/**
* Destroys all tokens except the new token.
*/
function tokenDelAll() {
$sessvars = array_keys($_SESSION);
$tokens = array();
foreach ($sessvars as $var) if(substr_compare($var,"spackt_",0,7)==0) $tokens[]=$var;
unset($tokens[array_search("spackt_".$this->token,$tokens)]);
foreach ($tokens as $token) unset($_SESSION[$token]);
}
/**
* Sets token.
*
* @access private
*/
private function tokenSet() {
$this->token = $this->tokenGen();
$_SESSION["spackt_".$this->token] = time();
}
/**
* Sets a token to protect a form. In fact, it prints a hidden field with the token.
*/
function protectForm() {
echo "<input type=\"hidden\" name=\"spack_token\" value=\"".$this->token."\" />";
}
/**
* Sets a token to protect a link. In fact, it puts in the querystring the token. Returns the protected link.
*
* @param string $link the link to protect.
* @return string
*/
function protectLink($link) {
if(strpos($link,"?")) return $link."&spack_token=".$this->token;
else return $link."?spack_token=".$this->token;
}
/**
* Checks if the request have the right token set; after that, destroy the old tokens. Returns true if the request is ok, otherwise returns false.
*/
function Check() {
// Check if the token has been sent.
if(isset($_REQUEST['spack_token'])) {
// Check if the token exists
if(isset($_SESSION["spackt_".$_REQUEST['spack_token']])) {
// Check if the token isn't empty
if(isset($_SESSION["spackt_".$_REQUEST['spack_token']])) {
$age = time()-$_SESSION["spackt_".$_REQUEST['spack_token']];
// Check if the token did not timeout
if($age > $this->timeout*60) $this->error = 4;
}
else $this->error = 3;
}
else $this->error = 2;
}
else $this->error = 1;
// Anyway, destroys the old token.
$this->tokenDelAll();
if($this->error==0) return true;
else return false;
}
/**
* Gets the error code.
*/
function Error() {
return $this->error;
}
}
?>