瀏覽代碼

ZF-8743: StripTags no longer allows whitelisting comments

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@20136 44c647ce-9c0f-0410-b52a-842ac1e357ba
matthew 16 年之前
父節點
當前提交
4420eb58b5

+ 2 - 4
documentation/manual/en/module_specs/Zend_Filter-Set.xml

@@ -106,13 +106,11 @@
             This filter returns the input string, with all HTML and <acronym>PHP</acronym> tags
             This filter returns the input string, with all HTML and <acronym>PHP</acronym> tags
             stripped from it, except those that have been explicitly allowed. In addition to the
             stripped from it, except those that have been explicitly allowed. In addition to the
             ability to specify which tags are allowed, developers can specify which attributes are
             ability to specify which tags are allowed, developers can specify which attributes are
-            allowed across all allowed tags and for specific tags only. Finally, this filter offers
-            control over whether comments (e.g., <command>&lt;!-- ... --&gt;</command>) are removed
-            or allowed.
+            allowed across all allowed tags and for specific tags only. 
         </para>
         </para>
     </sect2>
     </sect2>
 
 
 </sect1>
 </sect1>
 <!--
 <!--
 vim:se ts=4 sw=4 et:
 vim:se ts=4 sw=4 et:
--->
+-->

+ 17 - 1
documentation/manual/en/ref/migration-110.xml

@@ -120,7 +120,7 @@ $authors = $feed->getAuthors()->getValues();
         </sect3>
         </sect3>
     </sect2>
     </sect2>
 
 
-    <sect2 id="migration.19.zend.filter.html-entities">
+    <sect2 id="migration.110.zend.filter.html-entities">
         <title>Zend_Filter_HtmlEntities</title>
         <title>Zend_Filter_HtmlEntities</title>
 
 
         <para>
         <para>
@@ -141,6 +141,22 @@ $authors = $feed->getAuthors()->getValues();
         </para>
         </para>
     </sect2>
     </sect2>
 
 
+    <sect2 id="migration.110.zend.filter.strip-tags">
+        <title>Zend_Filter_StripTags</title>
+
+        <para>
+            <classname>Zend_Filter_StripTags</classname> contains a flag,
+            <varname>commentsAllowed</varname>, that, in previous versions, allowed you to
+            optionally whitelist HTML comments in HTML text filtered by the class. However, this
+            opens code enabling the flag to <acronym>XSS</acronym> attacks, particularly in Internet
+            Explorer (which allows specifying conditional functionality via HTML comments). Starting
+            in version 1.9.7 (and backported to versions 1.8.5 and 1.7.9), the
+            <varname>commentsAllowed</varname> flag no longer has any meaning, and all HTML
+            comments, including those containing other HTML tags or nested commments, will be
+            stripped from the final output of the filter.
+        </para>
+    </sect2>
+
     <sect2 id="migration.110.zend.translate">
     <sect2 id="migration.110.zend.translate">
         <title>Zend_Translate</title>
         <title>Zend_Translate</title>
 
 

+ 16 - 0
documentation/manual/en/ref/migration-19.xml

@@ -397,6 +397,22 @@ $container = new Zend_Navigation(array(
             please check your code and unit tests to ensure everything still continues to work.
             please check your code and unit tests to ensure everything still continues to work.
         </para>
         </para>
     </sect2>
     </sect2>
+
+    <sect2 id="migration.19.zend.filter.strip-tags">
+        <title>Zend_Filter_StripTags</title>
+
+        <para>
+            <classname>Zend_Filter_StripTags</classname> contains a flag,
+            <varname>commentsAllowed</varname>, that, in previous versions, allowed you to
+            optionally whitelist HTML comments in HTML text filtered by the class. However, this
+            opens code enabling the flag to <acronym>XSS</acronym> attacks, particularly in Internet
+            Explorer (which allows specifying conditional functionality via HTML comments). Starting
+            in version 1.9.7 (and backported to versions 1.8.5 and 1.7.9), the
+            <varname>commentsAllowed</varname> flag no longer has any meaning, and all HTML
+            comments, including those containing other HTML tags or nested commments, will be
+            stripped from the final output of the filter.
+        </para>
+    </sect2>
 </sect1>
 </sect1>
 <!--
 <!--
 vim:se ts=4 sw=4 et:
 vim:se ts=4 sw=4 et:

+ 14 - 19
library/Zend/Filter/StripTags.php

@@ -45,8 +45,10 @@ class Zend_Filter_StripTags implements Zend_Filter_Interface
      *
      *
      * If false (the default), then comments are removed from the input string.
      * If false (the default), then comments are removed from the input string.
      *
      *
-     * @var boolean
+     * This setting is now deprecated, and ignored internally.
+     *
      * @deprecated
      * @deprecated
+     * @var boolean
      */
      */
     public $commentsAllowed = false;
     public $commentsAllowed = false;
 
 
@@ -112,6 +114,11 @@ class Zend_Filter_StripTags implements Zend_Filter_Interface
 
 
     /**
     /**
      * Returns the commentsAllowed option
      * Returns the commentsAllowed option
+     *
+     * This setting is now deprecated and ignored internally.
+     *
+     * @deprecated
+     * @return bool
      */
      */
     public function getCommentsAllowed()
     public function getCommentsAllowed()
     {
     {
@@ -121,7 +128,10 @@ class Zend_Filter_StripTags implements Zend_Filter_Interface
     /**
     /**
      * Sets the commentsAllowed option
      * Sets the commentsAllowed option
      *
      *
-     * @param boolean $commentsAllowed
+     * This setting is now deprecated and ignored internally.
+     *
+     * @deprecated
+     * @param  boolean $commentsAllowed
      * @return Zend_Filter_StripTags Provides a fluent interface
      * @return Zend_Filter_StripTags Provides a fluent interface
      */
      */
     public function setCommentsAllowed($commentsAllowed)
     public function setCommentsAllowed($commentsAllowed)
@@ -227,16 +237,8 @@ class Zend_Filter_StripTags implements Zend_Filter_Interface
      */
      */
     public function filter($value)
     public function filter($value)
     {
     {
-        $valueCopy = (string) $value;
-
-        // If comments are allowed, then replace them with unique identifiers
-        if ($this->getCommentsAllowed()) {
-            preg_match_all('/<\!--.*?--\s*>/s' , (string) $valueCopy, $matches);
-            $comments = array_unique($matches[0]);
-            foreach ($comments as $k => $v) {
-                $valueCopy = str_replace($v, self::UNIQUE_ID_PREFIX . $k, $valueCopy);
-            }
-        }
+        // Strip HTML comments first
+        $valueCopy = preg_replace('#<!--(?:[^<]+|<(?!\!--))*?(--\s*>)#us', '', (string) $value);
 
 
         // Initialize accumulator for filtered data
         // Initialize accumulator for filtered data
         $dataFiltered = '';
         $dataFiltered = '';
@@ -260,13 +262,6 @@ class Zend_Filter_StripTags implements Zend_Filter_Interface
             $dataFiltered .= $preTag . $tagFiltered;
             $dataFiltered .= $preTag . $tagFiltered;
         }
         }
 
 
-        // If comments are allowed, then replace the unique identifiers with the corresponding comments
-        if ($this->getCommentsAllowed()) {
-            foreach ($comments as $k => $v) {
-                $dataFiltered = str_replace(self::UNIQUE_ID_PREFIX . $k, $v, $dataFiltered);
-            }
-        }
-
         // Return the filtered data
         // Return the filtered data
         return $dataFiltered;
         return $dataFiltered;
     }
     }

+ 19 - 12
tests/Zend/Filter/StripTagsTest.php

@@ -405,14 +405,15 @@ class Zend_Filter_StripTagsTest extends PHPUnit_Framework_TestCase
     }
     }
 
 
     /**
     /**
-     * Ensures that a comment is not removed when comments are allowed
+     * Ensures that a comment IS removed when comments are flagged as allowed
      *
      *
+     * @group ZF-8473
      * @return void
      * @return void
      */
      */
-    public function testFilterCommentAllowed()
+    public function testSpecifyingCommentsAllowedStillStripsComments()
     {
     {
         $input    = '<!-- a comment -->';
         $input    = '<!-- a comment -->';
-        $expected = '<!-- a comment -->';
+        $expected = '';
         $this->_filter->setCommentsAllowed(true);
         $this->_filter->setCommentsAllowed(true);
         $this->assertEquals($expected, $this->_filter->filter($input));
         $this->assertEquals($expected, $this->_filter->filter($input));
     }
     }
@@ -420,25 +421,29 @@ class Zend_Filter_StripTagsTest extends PHPUnit_Framework_TestCase
     /**
     /**
      * Ensures that a comment containing tags is untouched when comments are allowed
      * Ensures that a comment containing tags is untouched when comments are allowed
      *
      *
+     * @group ZF-8473
      * @return void
      * @return void
      */
      */
-    public function testFilterCommentAllowedContainsTags()
+    public function testSpecifyingCommentsAllowedStripsCommentsContainingTags()
     {
     {
         $input    = '<!-- a comment <br /> <h1>SuperLarge</h1> -->';
         $input    = '<!-- a comment <br /> <h1>SuperLarge</h1> -->';
-        $expected = '<!-- a comment <br /> <h1>SuperLarge</h1> -->';
+        $expected = '';
         $this->_filter->setCommentsAllowed(true);
         $this->_filter->setCommentsAllowed(true);
         $this->assertEquals($expected, $this->_filter->filter($input));
         $this->assertEquals($expected, $this->_filter->filter($input));
     }
     }
 
 
     /**
     /**
-     * Ensures expected behavior when comments are allowed and a comment contains tags and linebreaks
+     * Ensures expected behavior when comments are marked as allowed (in our 
+     * case, this should have no effect) and a comment contains tags and 
+     * linebreaks
      *
      *
+     * @group ZF-8473
      * @return void
      * @return void
      */
      */
-    public function testFilterCommentsAllowedContainsTagsLinebreaks()
+    public function testSpecifyingCommentsAllowedFiltersCommentsContainingTagsAndLinebreaks()
     {
     {
         $input    = "<br> test <p> text </p> with <!-- comments --> and <!-- hidd\n\nen <br> -->";
         $input    = "<br> test <p> text </p> with <!-- comments --> and <!-- hidd\n\nen <br> -->";
-        $expected = " test  text  with <!-- comments --> and <!-- hidd\n\nen <br> -->";
+        $expected = " test  text  with  and ";
         $this->_filter->setCommentsAllowed(true);
         $this->_filter->setCommentsAllowed(true);
         $this->assertEquals($expected, $this->_filter->filter($input));
         $this->assertEquals($expected, $this->_filter->filter($input));
     }
     }
@@ -446,26 +451,28 @@ class Zend_Filter_StripTagsTest extends PHPUnit_Framework_TestCase
     /**
     /**
      * Ensures expected behavior when comments are allowed but nested
      * Ensures expected behavior when comments are allowed but nested
      *
      *
+     * @group ZF-8473
      * @return void
      * @return void
      */
      */
-    public function testFilterCommentsAllowedNested()
+    public function testSpecifyingCommentsAllowedShouldStillStripNestedComments()
     {
     {
         $input    = '<a> <!-- <b> <!-- <c> --> <d> --> <e>';
         $input    = '<a> <!-- <b> <!-- <c> --> <d> --> <e>';
-        $expected = ' <!-- <b> <!-- <c> -->  -- ';
+        $expected = '   ';
         $this->_filter->setCommentsAllowed(true);
         $this->_filter->setCommentsAllowed(true);
         $this->assertEquals($expected, $this->_filter->filter($input));
         $this->assertEquals($expected, $this->_filter->filter($input));
     }
     }
 
 
     /**
     /**
-     * Ensures that space is allowed between the double-hyphen '--' and the ending delimiter '>'
+     * Ensures that space between double-hyphen and closing bracket still matches as a comment delimiter
      *
      *
+     * @group ZF-8473
      * @see    http://www.w3.org/TR/1999/REC-html401-19991224/intro/sgmltut.html#h-3.2.4
      * @see    http://www.w3.org/TR/1999/REC-html401-19991224/intro/sgmltut.html#h-3.2.4
      * @return void
      * @return void
      */
      */
     public function testFilterCommentsAllowedDelimiterEndingWhiteSpace()
     public function testFilterCommentsAllowedDelimiterEndingWhiteSpace()
     {
     {
         $input    = '<a> <!-- <b> --  > <c>';
         $input    = '<a> <!-- <b> --  > <c>';
-        $expected = ' <!-- <b> --  > ';
+        $expected = '  ';
         $this->_filter->setCommentsAllowed(true);
         $this->_filter->setCommentsAllowed(true);
         $this->assertEquals($expected, $this->_filter->filter($input));
         $this->assertEquals($expected, $this->_filter->filter($input));
     }
     }