CI framework security class Security.php source code analysis, cisecurity.php
The CI security class provides a global defense strategy against CSRF attacks and XSS attacks. You only need to enable it in the configuration file:
Copy code The code is as follows:
$config['csrf_protection'] = TRUE;
$config['global_xss_filtering'] = TRUE;
And provides practical methods:
Copy code The code is as follows:
$this->security->xss_clean($data);//The second parameter is TRUE to verify the security of the image
$this->security->sanitize_filename()//Filter file name
CI also provides security functions:
xss_clean()//xss filtering
sanitize_filename()//Sanitize file name
do_hash()//md5 or sha encryption
strip_image_tags() //Remove unnecessary characters of image tags
encode_php_tags()//Force PHP script tags into entity objects
Copy code The code is as follows:
/**
* Security category
*/
class CI_Security {
//Random hash value of url
protected $_xss_hash = '';
//Hash value of cookie tag to prevent CSRF attacks
protected $_csrf_hash = '';
//Anti-csrf cookie expiration time
protected $_csrf_expire = 7200;
//Csrf-proof cookie name
protected $_csrf_token_name = 'ci_csrf_token';
//Anti-csrf token name
protected $_csrf_cookie_name = 'ci_csrf_token';
//Array of strings that are not allowed
protected $_never_allowed_str = array(
'document.cookie' => '[removed]',
'document.write' => '[removed]',
'.parentNode' => '[removed]',
'.innerHTML' => '[removed]',
'window.location' => '[removed]',
'-moz-binding' => '[removed]',
'' => '-->',
' '
'
' => ''
);
//Array of regular expressions that are not allowed
protected $_never_allowed_regex = array(
'javascripts*:',
'expressions*((|()', // CSS and IE
'vbscripts*:', // IE, surprise!
'Redirects+302',
"(["'])?datas*:[^\1]*?base64[^\1]*?,[^\1]*?\1?"
);
//Constructor
public function __construct()
{
// Whether CSRF protection is enabled
if (config_item('csrf_protection') === TRUE)
{
// CSRF configuration
foreach (array('csrf_expire', 'csrf_token_name', 'csrf_cookie_name') as $key)
{
If (FALSE !== ($val = config_item($key)))
{
$this->{'_'.$key} = $val;
}
}
// _csrf_cookie_name plus cookie prefix
If (config_item('cookie_prefix'))
{
$this->_csrf_cookie_name = config_item('cookie_prefix').$this->_csrf_cookie_name;
}
//Set the hash value of csrf
$this->_csrf_set_hash();
}
log_message('debug', "Security Class Initialized");
}
//------------------------------------------------ ------------------
/**
* Verify Cross Site Request Forgery Protection
*
* @return object
*/
public function csrf_verify()
{
// If it is not a post request, set the cookie value of csrf
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();
}
//Does the token 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 the cookie value of csrf
*/
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;
}
//csrf保存
public function csrf_show_error()
{
show_error('The action you have requested is not allowed.');
}
//获取csrf的hash值
public function get_csrf_hash()
{
return $this->_csrf_hash;
}
//获取csrf的token值
public function get_csrf_token_name()
{
return $this->_csrf_token_name;
}
/**
* XSS filtering
*/
public function xss_clean($str, $is_image = FALSE)
{
//是否是数组
if (is_array($str))
{
while (list($key) = each($str))
{
$str[$key] = $this->xss_clean($str[$key]);
}
return $str;
}
//去掉可见字符串
$str = remove_invisible_characters($str);
// 验证实体url
$str = $this->_validate_entities($str);
/*
* URL 解码
*
* Just in case stuff like this is submitted:
*
* Google
*
* Note: Use rawurldecode() so it does not remove plus signs
*
*/
$str = rawurldecode($str);
/*
* Convert character entities to ASCII
*
* This permits our tests below to work reliably.
* We only convert entities that are within tags since
* these are the ones that will pose security problems.
*
*/
$str = preg_replace_callback("/[a-z]+=(['"]).*?\1/si", array($this, '_convert_attribute'), $str);
$str = preg_replace_callback("/|<|$)/si", array($this, '_decode_entity'), $str);
/*
* Remove Invisible Characters Again!
*/
$str = remove_invisible_characters($str);
/*
* Convert all tabs to spaces
*
* This prevents strings like this: ja vascript
* NOTE: we deal with spaces between characters later.
* NOTE: preg_replace was found to be amazingly slow here on
* large blocks of data, so we use str_replace.
*/
if (strpos($str, "t") !== FALSE)
{
$str = str_replace("t", ' ', $str);
}
/*
* Capture converted string for later comparison
*/
$converted_string = $str;
// Remove Strings that are never allowed
$str = $this->_do_never_allowed($str);
/*
* Makes PHP tags safe
*
* Note: XML tags are inadvertently replaced too:
*
*
*
* But it doesn't seem to pose a problem.
*/
if ($is_image === TRUE)
{
// Images have a tendency to have the PHP short opening and
// closing tags every so often so we skip those and only
// do the long opening tags.
$str = preg_replace('/(php)/i', "\1", $str);
}
else
{
$str = str_replace(array('', '?'.'>'), array('', '?>'), $str);
}
/*
* Compact any exploded words
*
* This corrects words like: j a v a s c r i p t
* These words are compacted back to their correct state.
*/
$words = array(
'javascript', 'expression', 'vbscript', 'script', 'base64',
'applet', 'alert', 'document', 'write', 'cookie', 'window'
);
foreach ($words as $word)
{
$temp = '';
for ($i = 0, $wordlen = strlen($word); $i < $wordlen; $i++)
{
$temp .= substr($word, $i, 1)."s*";
}
// We only want to do this when it is followed by a non-word character
// That way valid stuff like "dealer to" does not become "dealerto"
$str = preg_replace_callback('#('.substr($temp, 0, -3).')(W)#is', array($this, '_compact_exploded_words'), $str);
}
/*
* Remove disallowed Javascript in links or img tags
* We used to do some version comparisons and use of stripos for PHP5,
* but it is dog slow compared to these simplified non-capturing
* preg_match(), especially if the pattern exists in the string
*/
do
{
$original = $str;
if (preg_match("/
{
$str = preg_replace_callback("#]*?)(>|$)#si", array($this, '_js_link_removal'), $str);
}
if (preg_match("/
{
$str = preg_replace_callback("#]*?)(s?/?>|$)#si", array($this, '_js_img_removal'), $str);
}
if (preg_match("/script/i", $str) OR preg_match("/xss/i", $str))
{
$str = preg_replace("#<(/*)(script|xss)(.*?)>#si", '[removed]', $str);
}
}
while($original != $str);
unset($original);
// Remove evil attributes such as style, onclick and xmlns
$str = $this->_remove_evil_attributes($str, $is_image);
/*
* Sanitize naughty HTML elements
*
* If a tag containing any of the words in the list
* below is found, the tag gets converted to entities.
*
* So this: Statement:The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn