SECURITY: Improve css javascript detection
authorcsteipp <csteipp@wikimedia.org>
Tue, 8 Oct 2013 23:16:17 +0000 (16:16 -0700)
committercsteipp <csteipp@wikimedia.org>
Thu, 14 Nov 2013 22:32:51 +0000 (14:32 -0800)
* Forbid vertical tabs
* Convert Fullwidth, sup/sub script, IPA, and repetition unicode to
ascii, for ie6

Bug: 55332
Change-Id: I41a71b5b8fbecadd0f958cf57cc90d4c2fd9366e

includes/Sanitizer.php
tests/parser/parserTests.txt

index 4dbc9dd..3384af0 100644 (file)
@@ -865,6 +865,27 @@ class Sanitizer {
                $value = preg_replace_callback( $decodeRegex,
                        array( __CLASS__, 'cssDecodeCallback' ), $value );
 
+               // Normalize Halfwidth and Fullwidth Unicode block that IE6 might treat as ascii
+               $value = preg_replace_callback(
+                       '/[!-z]/u', // U+FF01 to U+FF5A
+                       function ( $matches ) {
+                               $cp = utf8ToCodepoint( $matches[0] );
+                               if ( $cp === false ) {
+                                       return '';
+                               }
+                               return chr( $cp - 65248 ); // ASCII range \x21-\x7A
+                       },
+                       $value
+               );
+
+               // Convert more characters IE6 might treat as ascii
+               // U+0280, U+0274, U+207F, U+029F, U+026A, U+207D, U+208D
+               $value = str_replace(
+                       array( 'ʀ', 'ɴ', 'ⁿ', 'ʟ', 'ɪ', '⁽', '₍' ),
+                       array( 'r', 'n', 'n', 'l', 'i', '(', '(' ),
+                       $value
+               );
+
                // Let the value through if it's nothing but a single comment, to
                // allow other functions which may reject it to pass some error
                // message through.
@@ -885,8 +906,24 @@ class Sanitizer {
                        }
                }
 
+               // S followed by repeat, iteration, or prolonged sound marks,
+               // which IE will treat as "ss"
+               $value = preg_replace(
+                       '/s(?:
+                               \xE3\x80\xB1 | # U+3031
+                               \xE3\x82\x9D | # U+309D
+                               \xE3\x83\xBC | # U+30FC
+                               \xE3\x83\xBD | # U+30FD
+                               \xEF\xB9\xBC | # U+FE7C
+                               \xEF\xB9\xBD | # U+FE7D
+                               \xEF\xBD\xB0   # U+FF70
+                       )/ix',
+                       'ss',
+                       $value
+               );
+
                // Reject problematic keywords and control characters
-               if ( preg_match( '/[\000-\010\016-\037\177]/', $value ) ) {
+               if ( preg_match( '/[\000-\010\013\016-\037\177]/', $value ) ) {
                        return '/* invalid control char */';
                } elseif ( preg_match( '! expression | filter\s*: | accelerator\s*: | url\s*\( | image\s*\( | image-set\s*\( !ix', $value ) ) {
                        return '/* insecure input */';
index d4d9f43..cc935da 100644 (file)
@@ -11709,6 +11709,70 @@ MSIE CSS safety test: comment in expression
 
 !! end
 
+!! test
+CSS safety test: vertical tab
+!! input
+<p style="font-size: 100px; background-image:url\b(https://www.google.com/images/srpr/logo6w.png)">A</p>
+!! result
+<p style="/* invalid control char */">A</p>
+
+!! end
+
+!! test
+MSIE CSS safety test: Fullwidth
+!! input
+<p style="font-size: 100px; color: expression((title='XSSed'),'red')">A</p>
+<div style="top:EXPRESSION(alert())">B</div>
+!! result
+<p style="/* insecure input */">A</p>
+<div style="/* insecure input */">B</div>
+
+!! end
+
+!! test
+MSIE CSS safety test: IPA extensions
+!! input
+<div style="background-image:uʀʟ(javascript:alert())">A</div>
+<p style="font-size: 100px; color: expʀessɪoɴ((title='XSSed'),'red')">B</p>
+!! result
+<div style="/* insecure input */">A</div>
+<p style="/* insecure input */">B</p>
+
+!! end
+
+!! test
+MSIE CSS safety test: sup/sub script
+!! input
+<div style="background-image:url⁽javascript:alert())">A</div>
+<div style="background-image:url₍javascript:alert())">B</div>
+<p style="font-size: 100px; color: expressioⁿ((title='XSSed'),'red')">C</p>
+!! result
+<div style="/* insecure input */">A</div>
+<div style="/* insecure input */">B</div>
+<p style="/* insecure input */">C</p>
+
+!! end
+
+!! test
+MSIE CSS safety test: Repetition markers
+!! input
+<p style="font-size: 100px; color: expres〱ion((title='XSSed'),'red')">A</p>
+<p style="font-size: 100px; color: expresゝion((title='XSSed'),'red')">B</p>
+<p style="font-size: 100px; color: expresーion((title='XSSed'),'red')">C</p>
+<p style="font-size: 100px; color: expresヽion((title='XSSed'),'red')">D</p>
+<p style="font-size: 100px; color: expresﹽion((title='XSSed'),'red')">E</p>
+<p style="font-size: 100px; color: expresﹼion((title='XSSed'),'red')">F</p>
+<p style="font-size: 100px; color: expresーion((title='XSSed'),'red')">G</p>
+!! result
+<p style="/* insecure input */">A</p>
+<p style="/* insecure input */">B</p>
+<p style="/* insecure input */">C</p>
+<p style="/* insecure input */">D</p>
+<p style="/* insecure input */">E</p>
+<p style="/* insecure input */">F</p>
+<p style="/* insecure input */">G</p>
+
+!! end
 
 !! test
 Table attribute legitimate extension