876 lines
22 KiB
PHP
876 lines
22 KiB
PHP
|
|
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
|
||
|
|
/**
|
||
|
|
* CodeIgniter
|
||
|
|
*
|
||
|
|
* An open source application development framework for PHP 5.1.6 or newer
|
||
|
|
*
|
||
|
|
* @package CodeIgniter
|
||
|
|
* @author ExpressionEngine Dev Team
|
||
|
|
* @copyright Copyright (c) 2008 - 2011, EllisLab, Inc.
|
||
|
|
* @license http://codeigniter.com/user_guide/license.html
|
||
|
|
* @link http://codeigniter.com
|
||
|
|
* @since Version 1.0
|
||
|
|
* @filesource
|
||
|
|
*/
|
||
|
|
|
||
|
|
// ------------------------------------------------------------------------
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Security Class
|
||
|
|
*
|
||
|
|
* @package CodeIgniter
|
||
|
|
* @subpackage Libraries
|
||
|
|
* @category Security
|
||
|
|
* @author ExpressionEngine Dev Team
|
||
|
|
* @link http://codeigniter.com/user_guide/libraries/security.html
|
||
|
|
*/
|
||
|
|
class CI_Security {
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Random Hash for protecting URLs
|
||
|
|
*
|
||
|
|
* @var string
|
||
|
|
* @access protected
|
||
|
|
*/
|
||
|
|
protected $_xss_hash = '';
|
||
|
|
/**
|
||
|
|
* Random Hash for Cross Site Request Forgery Protection Cookie
|
||
|
|
*
|
||
|
|
* @var string
|
||
|
|
* @access protected
|
||
|
|
*/
|
||
|
|
protected $_csrf_hash = '';
|
||
|
|
/**
|
||
|
|
* Expiration time for Cross Site Request Forgery Protection Cookie
|
||
|
|
* Defaults to two hours (in seconds)
|
||
|
|
*
|
||
|
|
* @var int
|
||
|
|
* @access protected
|
||
|
|
*/
|
||
|
|
protected $_csrf_expire = 7200;
|
||
|
|
/**
|
||
|
|
* Token name for Cross Site Request Forgery Protection Cookie
|
||
|
|
*
|
||
|
|
* @var string
|
||
|
|
* @access protected
|
||
|
|
*/
|
||
|
|
protected $_csrf_token_name = 'ci_csrf_token';
|
||
|
|
/**
|
||
|
|
* Cookie name for Cross Site Request Forgery Protection Cookie
|
||
|
|
*
|
||
|
|
* @var string
|
||
|
|
* @access protected
|
||
|
|
*/
|
||
|
|
protected $_csrf_cookie_name = 'ci_csrf_token';
|
||
|
|
/**
|
||
|
|
* List of never allowed strings
|
||
|
|
*
|
||
|
|
* @var array
|
||
|
|
* @access protected
|
||
|
|
*/
|
||
|
|
protected $_never_allowed_str = array(
|
||
|
|
'document.cookie' => '[removed]',
|
||
|
|
'document.write' => '[removed]',
|
||
|
|
'.parentNode' => '[removed]',
|
||
|
|
'.innerHTML' => '[removed]',
|
||
|
|
'window.location' => '[removed]',
|
||
|
|
'-moz-binding' => '[removed]',
|
||
|
|
'<!--' => '<!--',
|
||
|
|
'-->' => '-->',
|
||
|
|
'<![CDATA[' => '<![CDATA[',
|
||
|
|
'<comment>' => '<comment>'
|
||
|
|
);
|
||
|
|
|
||
|
|
/* never allowed, regex replacement */
|
||
|
|
/**
|
||
|
|
* List of never allowed regex replacement
|
||
|
|
*
|
||
|
|
* @var array
|
||
|
|
* @access protected
|
||
|
|
*/
|
||
|
|
protected $_never_allowed_regex = array(
|
||
|
|
'javascript\s*:',
|
||
|
|
'expression\s*(\(|&\#40;)', // CSS and IE
|
||
|
|
'vbscript\s*:', // IE, surprise!
|
||
|
|
'Redirect\s+302',
|
||
|
|
"([\"'])?data\s*:[^\\1]*?base64[^\\1]*?,[^\\1]*?\\1?"
|
||
|
|
);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Constructor
|
||
|
|
*
|
||
|
|
* @return void
|
||
|
|
*/
|
||
|
|
public function __construct()
|
||
|
|
{
|
||
|
|
// Is CSRF protection enabled?
|
||
|
|
if (config_item('csrf_protection') === TRUE)
|
||
|
|
{
|
||
|
|
// CSRF config
|
||
|
|
foreach (array('csrf_expire', 'csrf_token_name', 'csrf_cookie_name') as $key)
|
||
|
|
{
|
||
|
|
if (FALSE !== ($val = config_item($key)))
|
||
|
|
{
|
||
|
|
$this->{'_'.$key} = $val;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Append application specific cookie prefix
|
||
|
|
if (config_item('cookie_prefix'))
|
||
|
|
{
|
||
|
|
$this->_csrf_cookie_name = config_item('cookie_prefix').$this->_csrf_cookie_name;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Set the CSRF hash
|
||
|
|
$this->_csrf_set_hash();
|
||
|
|
}
|
||
|
|
|
||
|
|
log_message('debug', "Security Class Initialized");
|
||
|
|
}
|
||
|
|
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Verify Cross Site Request Forgery Protection
|
||
|
|
*
|
||
|
|
* @return object
|
||
|
|
*/
|
||
|
|
public function csrf_verify()
|
||
|
|
{
|
||
|
|
// If it's not a POST request we will set the CSRF cookie
|
||
|
|
if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST')
|
||
|
|
{
|
||
|
|
return $this->csrf_set_cookie();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Do the tokens exist in both the _POST and _COOKIE arrays?
|
||
|
|
if ( ! isset($_POST[$this->_csrf_token_name], $_COOKIE[$this->_csrf_cookie_name]))
|
||
|
|
{
|
||
|
|
$this->csrf_show_error();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Do the tokens match?
|
||
|
|
if ($_POST[$this->_csrf_token_name] != $_COOKIE[$this->_csrf_cookie_name])
|
||
|
|
{
|
||
|
|
$this->csrf_show_error();
|
||
|
|
}
|
||
|
|
|
||
|
|
// We kill this since we're done and we don't want to
|
||
|
|
// polute the _POST array
|
||
|
|
unset($_POST[$this->_csrf_token_name]);
|
||
|
|
|
||
|
|
// Nothing should last forever
|
||
|
|
unset($_COOKIE[$this->_csrf_cookie_name]);
|
||
|
|
$this->_csrf_set_hash();
|
||
|
|
$this->csrf_set_cookie();
|
||
|
|
|
||
|
|
log_message('debug', 'CSRF token verified');
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Set Cross Site Request Forgery Protection Cookie
|
||
|
|
*
|
||
|
|
* @return object
|
||
|
|
*/
|
||
|
|
public function csrf_set_cookie()
|
||
|
|
{
|
||
|
|
$expire = time() + $this->_csrf_expire;
|
||
|
|
$secure_cookie = (config_item('cookie_secure') === TRUE) ? 1 : 0;
|
||
|
|
|
||
|
|
if ($secure_cookie && (empty($_SERVER['HTTPS']) OR strtolower($_SERVER['HTTPS']) === 'off'))
|
||
|
|
{
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
setcookie($this->_csrf_cookie_name, $this->_csrf_hash, $expire, config_item('cookie_path'), config_item('cookie_domain'), $secure_cookie);
|
||
|
|
|
||
|
|
log_message('debug', "CRSF cookie Set");
|
||
|
|
|
||
|
|
return $this;
|
||
|
|
}
|
||
|
|
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Show CSRF Error
|
||
|
|
*
|
||
|
|
* @return void
|
||
|
|
*/
|
||
|
|
public function csrf_show_error()
|
||
|
|
{
|
||
|
|
show_error('The action you have requested is not allowed.');
|
||
|
|
}
|
||
|
|
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get CSRF Hash
|
||
|
|
*
|
||
|
|
* Getter Method
|
||
|
|
*
|
||
|
|
* @return string self::_csrf_hash
|
||
|
|
*/
|
||
|
|
public function get_csrf_hash()
|
||
|
|
{
|
||
|
|
return $this->_csrf_hash;
|
||
|
|
}
|
||
|
|
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get CSRF Token Name
|
||
|
|
*
|
||
|
|