summaryrefslogtreecommitdiffstats
path: root/system/core/Security.php
diff options
context:
space:
mode:
Diffstat (limited to 'system/core/Security.php')
-rwxr-xr-xsystem/core/Security.php151
1 files changed, 78 insertions, 73 deletions
diff --git a/system/core/Security.php b/system/core/Security.php
index 342455f27..ce3f7d3cc 100755
--- a/system/core/Security.php
+++ b/system/core/Security.php
@@ -4,10 +4,22 @@
*
* An open source application development framework for PHP 5.1.6 or newer
*
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst. It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
* @package CodeIgniter
- * @author ExpressionEngine Dev Team
- * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc.
- * @license http://codeigniter.com/user_guide/license.html
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* @link http://codeigniter.com
* @since Version 1.0
* @filesource
@@ -21,7 +33,7 @@
* @package CodeIgniter
* @subpackage Libraries
* @category Security
- * @author ExpressionEngine Dev Team
+ * @author EllisLab Dev Team
* @link http://codeigniter.com/user_guide/libraries/security.html
*/
class CI_Security {
@@ -33,7 +45,7 @@ class CI_Security {
* @access protected
*/
protected $_xss_hash = '';
-
+
/**
* Random Hash for Cross Site Request Forgery Protection Cookie
*
@@ -41,7 +53,7 @@ class CI_Security {
* @access protected
*/
protected $_csrf_hash = '';
-
+
/**
* Expiration time for Cross Site Request Forgery Protection Cookie
* Defaults to two hours (in seconds)
@@ -50,7 +62,7 @@ class CI_Security {
* @access protected
*/
protected $_csrf_expire = 7200;
-
+
/**
* Token name for Cross Site Request Forgery Protection Cookie
*
@@ -58,7 +70,7 @@ class CI_Security {
* @access protected
*/
protected $_csrf_token_name = 'ci_csrf_token';
-
+
/**
* Cookie name for Cross Site Request Forgery Protection Cookie
*
@@ -66,14 +78,14 @@ class CI_Security {
* @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]',
@@ -83,7 +95,8 @@ class CI_Security {
'-moz-binding' => '[removed]',
'<!--' => '&lt;!--',
'-->' => '--&gt;',
- '<![CDATA[' => '&lt;![CDATA['
+ '<![CDATA[' => '&lt;![CDATA[',
+ '<comment>' => '&lt;comment&gt;'
);
/**
@@ -139,7 +152,7 @@ class CI_Security {
{
return $this->csrf_set_cookie();
}
-
+
// Check if URI has been whitelisted from CSRF checks
if ($exclude_uris = config_item('csrf_exclude_uris'))
{
@@ -169,11 +182,12 @@ class CI_Security {
// Nothing should last forever
unset($_COOKIE[$this->_csrf_cookie_name]);
+ $this->_csrf_hash = '';
$this->_csrf_set_hash();
$this->csrf_set_cookie();
-
+
log_message('debug', "CSRF token verified");
-
+
return $this;
}
@@ -187,7 +201,7 @@ class CI_Security {
public function csrf_set_cookie()
{
$expire = time() + $this->_csrf_expire;
- $secure_cookie = (config_item('cookie_secure') === TRUE) ? 1 : 0;
+ $secure_cookie = (bool) config_item('cookie_secure');
if ($secure_cookie)
{
@@ -384,16 +398,11 @@ class CI_Security {
foreach ($words as $word)
{
- $temp = '';
-
- for ($i = 0, $wordlen = strlen($word); $i < $wordlen; $i++)
- {
- $temp .= substr($word, $i, 1)."\s*";
- }
+ $word = implode("\s*", str_split($word)) . "\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);
+ $str = preg_replace_callback('#('.substr($word, 0, -3).')(\W)#is', array($this, '_compact_exploded_words'), $str);
}
/*
@@ -472,7 +481,7 @@ class CI_Security {
if ($is_image === TRUE)
{
- return ($str == $converted_string) ? TRUE: FALSE;
+ return ($str === $converted_string) ? TRUE : FALSE;
}
log_message('debug', "XSS Filtering completed");
@@ -490,15 +499,7 @@ class CI_Security {
{
if ($this->_xss_hash == '')
{
- if (phpversion() >= 4.2)
- {
- mt_srand();
- }
- else
- {
- mt_srand(hexdec(substr(md5(microtime()), -8)) & 0x7fffffff);
- }
-
+ mt_srand();
$this->_xss_hash = md5(time() + mt_rand(0, 1999999999));
}
@@ -512,48 +513,31 @@ class CI_Security {
*
* This function is a replacement for html_entity_decode()
*
- * In some versions of PHP the native function does not work
- * when UTF-8 is the specified character set, so this gives us
- * a work-around. More info here:
- * http://bugs.php.net/bug.php?id=25670
- *
- * NOTE: html_entity_decode() has a bug in some PHP versions when UTF-8 is the
- * character set, and the PHP developers said they were not back porting the
- * fix to versions other than PHP 5.x.
+ * The reason we are not using html_entity_decode() by itself is because
+ * while it is not technically correct to leave out the semicolon
+ * at the end of an entity most browsers will still interpret the entity
+ * correctly. html_entity_decode() does not convert entities without
+ * semicolons, so we are left with our own little solution here. Bummer.
*
* @param string
* @param string
* @return string
*/
- public function entity_decode($str, $charset='UTF-8')
+ public function entity_decode($str, $charset = NULL)
{
- if (stristr($str, '&') === FALSE) return $str;
-
- // The reason we are not using html_entity_decode() by itself is because
- // while it is not technically correct to leave out the semicolon
- // at the end of an entity most browsers will still interpret the entity
- // correctly. html_entity_decode() does not convert entities without
- // semicolons, so we are left with our own little solution here. Bummer.
-
- if (function_exists('html_entity_decode') &&
- (strtolower($charset) != 'utf-8'))
+ if (strpos($str, '&') === FALSE)
{
- $str = html_entity_decode($str, ENT_COMPAT, $charset);
- $str = preg_replace('~&#x(0*[0-9a-f]{2,5})~ei', 'chr(hexdec("\\1"))', $str);
- return preg_replace('~&#([0-9]{2,4})~e', 'chr(\\1)', $str);
+ return $str;
}
- // Numeric Entities
- $str = preg_replace('~&#x(0*[0-9a-f]{2,5});{0,1}~ei', 'chr(hexdec("\\1"))', $str);
- $str = preg_replace('~&#([0-9]{2,4});{0,1}~e', 'chr(\\1)', $str);
-
- // Literal Entities - Slightly slow so we do another check
- if (stristr($str, '&') === FALSE)
+ if (empty($charset))
{
- $str = strtr($str, array_flip(get_html_translation_table(HTML_ENTITIES)));
+ $charset = config_item('charset');
}
- return $str;
+ $str = html_entity_decode($str, ENT_COMPAT, $charset);
+ $str = preg_replace('~&#x(0*[0-9a-f]{2,5})~ei', 'chr(hexdec("\\1"))', $str);
+ return preg_replace('~&#([0-9]{2,4})~e', 'chr(\\1)', $str);
}
// --------------------------------------------------------------------
@@ -647,25 +631,45 @@ class CI_Security {
protected function _remove_evil_attributes($str, $is_image)
{
// All javascript event handlers (e.g. onload, onclick, onmouseover), style, and xmlns
- $evil_attributes = array('on\w*', 'style', 'xmlns');
+ $evil_attributes = array('on\w*', 'style', 'xmlns', 'formaction');
if ($is_image === TRUE)
{
/*
- * Adobe Photoshop puts XML metadata into JFIF images,
+ * Adobe Photoshop puts XML metadata into JFIF images,
* including namespacing, so we have to allow this for images.
*/
unset($evil_attributes[array_search('xmlns', $evil_attributes)]);
}
-
+
do {
- $str = preg_replace(
- "#<(/?[^><]+?)([^A-Za-z\-])(".implode('|', $evil_attributes).")(\s*=\s*)([\"][^>]*?[\"]|[\'][^>]*?[\']|[^>]*?)([\s><])([><]*)#i",
- "<$1$6",
- $str, -1, $count
- );
- } while ($count);
+ $count = 0;
+ $attribs = array();
+
+ // find occurrences of illegal attribute strings without quotes
+ preg_match_all("/(".implode('|', $evil_attributes).")\s*=\s*([^\s]*)/is", $str, $matches, PREG_SET_ORDER);
+
+ foreach ($matches as $attr)
+ {
+ $attribs[] = preg_quote($attr[0], '/');
+ }
+
+ // find occurrences of illegal attribute strings with quotes (042 and 047 are octal quotes)
+ preg_match_all("/(".implode('|', $evil_attributes).")\s*=\s*(\042|\047)([^\\2]*?)(\\2)/is", $str, $matches, PREG_SET_ORDER);
+
+ foreach ($matches as $attr)
+ {
+ $attribs[] = preg_quote($attr[0], '/');
+ }
+ // replace illegal attribute strings that are inside an html tag
+ if (count($attribs) > 0)
+ {
+ $str = preg_replace("/<(\/?[^><]+?)([^A-Za-z\-])(".implode('|', $attribs).")([\s><])([><]*)/i", '<$1$2$4$5', $str, -1, $count);
+ }
+
+ } while ($count);
+
return $str;
}
@@ -877,7 +881,8 @@ class CI_Security {
return $this->_csrf_hash = $_COOKIE[$this->_csrf_cookie_name];
}
- return $this->_csrf_hash = md5(uniqid(rand(), TRUE));
+ $this->_csrf_hash = md5(uniqid(rand(), TRUE));
+ $this->csrf_set_cookie();
}
return $this->_csrf_hash;
@@ -886,4 +891,4 @@ class CI_Security {
}
/* End of file Security.php */
-/* Location: ./system/libraries/Security.php */ \ No newline at end of file
+/* Location: ./system/core/Security.php */ \ No newline at end of file