开发者

Zend Framework Input/Output XSS Filtering: Strip Tags, Textile, BBCode

开发者 https://www.devze.com 2023-04-12 16:57 出处:网络
In my CMS application, administration users can add HTML content via a WYSIWYG editor that gets filtered by HTMLPurifier.I am no开发者_开发知识库w wanting to add a message board functionality. I am pl

In my CMS application, administration users can add HTML content via a WYSIWYG editor that gets filtered by HTMLPurifier. I am no开发者_开发知识库w wanting to add a message board functionality. I am planning on using the Zend StripTags Filter without a whitelist to remove all HTML, and then provide for rich markup by using Zend's BBCode or Textile parsers.

These are my questions:

  1. Can XSS make it through StripTags if I have no whitelist?
  2. Does adding BBCode or Textile as an output parser reintroduce the possibility of XSS?


After reading a post about Markdown here on SO, and another article linked in an answer to that post, it appears that reintroducing XSS into a document is not only possible, but trivial. To be secure, I will need to run content through HTMLPurifier as the final step in the output filter chain. Because I am concerned with the performance of HTMLPurifier as an output filter, I am looking into using Wibble instead.

This still leaves the first question unanswered, but in my case, that step will be unnecessary.


I discovered when trying to use them, that Zend's BBCode and Textile are horribly buggy. I instead used PHP Markdown. Also, Wibble doesn't seem like it's production ready yet.

I used two columns in my database: content and html. The content column holds the user-submitted text. When saving the record, I convert content to HTML with PHP Markdown, pass it through HTMLPurifier and then save that value to the html column. I am not converting will every view that way.


Implementation Details

I put PHP Markdown here: library/markdown.php. In my active record model, using Zend_Db_Table_Row_Abstract, I use the _insert() and _update() hooks to process the values before the record is saved:

// prepare html based on the content
require_once 'markdown.php';
$flt = new My_Filter_HtmlPurifier();
$this->html = $flt->filter(Markdown($this->content));

Here is my HTMLPurifier filter:

/**
 * Based on examples from http://blog.astrumfutura.com/archives/365-Example-Zend-Framework-Blog-Application-Tutorial-Part-8-Creating-and-Editing-Blog-Entries-with-a-dash-of-HTMLPurifier.html
 */
require_once 'HTMLPurifier.includes.php';
require_once 'HTMLPurifier.autoload.php';

class My_Filter_HtmlPurifier implements Zend_Filter_Interface
{
    /** @var HTMLPurifier */
    protected $_htmlPurifier;

    public function __construct($options = null)
    {
        // set up configuration
        $config = HTMLPurifier_Config::createDefault();
        $config->set('HTML.DefinitionID', 'My HTML Purifier Filter');
        $config->set('HTML.DefinitionRev', 3); // increment when configuration changes
//        $config->set('Cache.DefinitionImpl', null); // comment out after finalizing the config

        // Doctype
        $config->set('HTML.Doctype', 'XHTML 1.0 Transitional');

        // Add support for object (flash) tags
        $config->set('HTML.SafeObject', true);
        $config->set('Output.FlashCompat', true); // IE Support

        // Custom Filters
        // Add support for iframes - YouTube, Vimeo...
        $config->set('Filter.Custom', array(new HTMLPurifier_Filter_MyIframe()));

        // Add support for anchor targets
        $config->set('Attr.AllowedFrameTargets', array('_blank', '_self', '_target', '_top'));

        // configure caching
        $cachePath = CUST_APP_PATH . '/../cache/htmlpurifier';
        if (!is_dir($cachePath)) {
            mkdir($cachePath, 0700, true);
        }
        $cachePath = realpath($cachePath);
        $config->set('Cache.SerializerPath', $cachePath);

        // allow for passed-in options
        if (!is_null($options)) {
            //$config = HTMLPurifier_Config::createDefault();
            foreach ($options as $option) {
                $config->set($option[0], $option[1], $option[2]);
            }
        }

        // create the local instance
        $this->_htmlPurifier = new HTMLPurifier($config);
    }

    public function filter($value)
    {
        return $this->_htmlPurifier->purify($value);
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号