summaryrefslogtreecommitdiffstats
path: root/system/core
diff options
context:
space:
mode:
authorAndrey Andreev <narf@devilix.net>2015-11-04 14:43:11 +0100
committerAndrey Andreev <narf@devilix.net>2015-11-04 14:43:11 +0100
commit66a8940823b8ce9cd9e0bfe5d4263008a437a422 (patch)
tree0d02a82cce7adfbfeee51e2a4a7257c74f906551 /system/core
parent175b17c4b74d03a7578440d92a3ac9d80924ef78 (diff)
parentab3c383fb3535e55253271f210870cd9361d94c9 (diff)
Merge branch '3.0-stable' into develop
Diffstat (limited to 'system/core')
-rw-r--r--system/core/Common.php7
-rw-r--r--system/core/Config.php6
-rw-r--r--system/core/Security.php66
3 files changed, 47 insertions, 32 deletions
diff --git a/system/core/Common.php b/system/core/Common.php
index ad3ca9f93..3ab98cf6d 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -752,7 +752,12 @@ if ( ! function_exists('html_escape'))
if (is_array($var))
{
- return array_map('html_escape', $var, array_fill(0, count($var), $double_encode));
+ foreach (array_keys($var) as $key)
+ {
+ $var[$key] = html_escape($var[$key], $double_encode);
+ }
+
+ return $var;
}
return htmlspecialchars($var, ENT_QUOTES, config_item('charset'), $double_encode);
diff --git a/system/core/Config.php b/system/core/Config.php
index feea7c85a..0264776f9 100644
--- a/system/core/Config.php
+++ b/system/core/Config.php
@@ -88,11 +88,9 @@ class CI_Config {
// Set the base_url automatically if none was provided
if (empty($this->config['base_url']))
{
- // The regular expression is only a basic validation for a valid "Host" header.
- // It's not exhaustive, only checks for valid characters.
- if (isset($_SERVER['HTTP_HOST']) && preg_match('/^((\[[0-9a-f:]+\])|(\d{1,3}(\.\d{1,3}){3})|[a-z0-9\-\.]+)(:\d+)?$/i', $_SERVER['HTTP_HOST']))
+ if (isset($_SERVER['SERVER_ADDR']))
{
- $base_url = (is_https() ? 'https' : 'http').'://'.$_SERVER['HTTP_HOST']
+ $base_url = (is_https() ? 'https' : 'http').'://'.$_SERVER['SERVER_ADDR']
.substr($_SERVER['SCRIPT_NAME'], 0, strpos($_SERVER['SCRIPT_NAME'], basename($_SERVER['SCRIPT_FILENAME'])));
}
else
diff --git a/system/core/Security.php b/system/core/Security.php
index ab85e2239..36dea4cf2 100644
--- a/system/core/Security.php
+++ b/system/core/Security.php
@@ -803,43 +803,55 @@ class CI_Security {
// For other tags, see if their attributes are "evil" and strip those
elseif (isset($matches['attributes']))
{
- // We'll need to catch all attributes separately first
- $pattern = '#'
- .'([\s\042\047/=]*)' // non-attribute characters, excluding > (tag close) for obvious reasons
+ // We'll store the already fitlered attributes here
+ $attributes = array();
+
+ // Attribute-catching pattern
+ $attributes_pattern = '#'
.'(?<name>[^\s\042\047>/=]+)' // attribute characters
// optional attribute-value
.'(?:\s*=(?<value>[^\s\042\047=><`]+|\s*\042[^\042]*\042|\s*\047[^\047]*\047|\s*(?U:[^\s\042\047=><`]*)))' // attribute-value separator
.'#i';
- if ($count = preg_match_all($pattern, $matches['attributes'], $attributes, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
+ // Blacklist pattern for evil attribute names
+ $is_evil_pattern = '#^('.implode('|', $evil_attributes).')$#i';
+
+ // Each iteration filters a single attribute
+ do
{
- // Since we'll be using substr_replace() below, we
- // need to handle the attributes in reverse order,
- // so we don't damage the string.
- for ($i = $count - 1; $i > -1; $i--)
+ // Strip any non-alpha characters that may preceed an attribute.
+ // Browsers often parse these incorrectly and that has been a
+ // of numerous XSS issues we've had.
+ $matches['attributes'] = preg_replace('#^[^a-z]+#i', '', $matches['attributes']);
+
+ if ( ! preg_match($attributes_pattern, $matches['attributes'], $attribute, PREG_OFFSET_CAPTURE))
{
- if (
- // Is it indeed an "evil" attribute?
- preg_match('#^('.implode('|', $evil_attributes).')$#i', $attributes[$i]['name'][0])
- // Or an attribute not starting with a letter? Some parsers get confused by that
- OR ! ctype_alpha($attributes[$i]['name'][0][0])
- // Does it have an equals sign, but no value and not quoted? Strip that too!
- OR (trim($attributes[$i]['value'][0]) === '')
- )
- {
- $matches['attributes'] = substr_replace(
- $matches['attributes'],
- ' [removed]',
- $attributes[$i][0][1],
- strlen($attributes[$i][0][0])
- );
- }
+ // No (valid) attribute found? Discard everything else inside the tag
+ break;
}
- // Note: This will strip some non-space characters and/or
- // reduce multiple spaces between attributes.
- return '<'.$matches['slash'].$matches['tagName'].' '.trim($matches['attributes']).'>';
+ if (
+ // Is it indeed an "evil" attribute?
+ preg_match($is_evil_pattern, $attribute['name'][0])
+ // Or does it have an equals sign, but no value and not quoted? Strip that too!
+ OR (trim($attribute['value'][0]) === '')
+ )
+ {
+ $attributes[] = 'xss=removed';
+ }
+ else
+ {
+ $attributes[] = $attribute[0][0];
+ }
+
+ $matches['attributes'] = substr($matches['attributes'], $attribute[0][1] + strlen($attribute[0][0]));
}
+ while ($matches['attributes'] !== '');
+
+ $attributes = empty($attributes)
+ ? ''
+ : ' '.implode(' ', $attributes);
+ return '<'.$matches['slash'].$matches['tagName'].$attributes.'>';
}
return $matches[0];