diff options
Diffstat (limited to 'includes/Sanitizer.php')
-rw-r--r-- | includes/Sanitizer.php | 50 |
1 files changed, 37 insertions, 13 deletions
diff --git a/includes/Sanitizer.php b/includes/Sanitizer.php index 5d58b036..0b70e002 100644 --- a/includes/Sanitizer.php +++ b/includes/Sanitizer.php @@ -658,24 +658,48 @@ class Sanitizer { * @return mixed */ static function checkCss( $value ) { - $stripped = Sanitizer::decodeCharReferences( $value ); + $value = Sanitizer::decodeCharReferences( $value ); // Remove any comments; IE gets token splitting wrong - $stripped = StringUtils::delimiterReplace( '/*', '*/', ' ', $stripped ); - - $value = $stripped; - - // ... and continue checks - $stripped = preg_replace( '!\\\\([0-9A-Fa-f]{1,6})[ \\n\\r\\t\\f]?!e', - 'codepointToUtf8(hexdec("$1"))', $stripped ); - $stripped = str_replace( '\\', '', $stripped ); - if( preg_match( '/(?:expression|tps*:\/\/|url\\s*\().*/is', - $stripped ) ) { - # haxx0r + $value = StringUtils::delimiterReplace( '/*', '*/', ' ', $value ); + + // Decode escape sequences and line continuation + // See the grammar in the CSS 2 spec, appendix D, Mozilla implements it accurately. + // IE 8 doesn't implement it at all, but there's no way to introduce url() into + // IE that doesn't hit Mozilla also. + static $decodeRegex; + if ( !$decodeRegex ) { + $space = '[\\x20\\t\\r\\n\\f]'; + $nl = '(?:\\n|\\r\\n|\\r|\\f)'; + $backslash = '\\\\'; + $decodeRegex = "/ $backslash + (?: + ($nl) | # 1. Line continuation + ([0-9A-Fa-f]{1,6})$space? | # 2. character number + (.) # 3. backslash cancelling special meaning + )/xu"; + } + $decoded = preg_replace_callback( $decodeRegex, + array( __CLASS__, 'cssDecodeCallback' ), $value ); + if ( preg_match( '!expression|https?://|url\s*\(!i', $decoded ) ) { + // Not allowed return false; + } else { + // Allowed, return CSS with comments stripped + return $value; } + } - return $value; + static function cssDecodeCallback( $matches ) { + if ( $matches[1] !== '' ) { + return ''; + } elseif ( $matches[2] !== '' ) { + return codepointToUtf8( hexdec( $matches[2] ) ); + } elseif ( $matches[3] !== '' ) { + return $matches[3]; + } else { + throw new MWException( __METHOD__.': invalid match' ); + } } /** |