OWASP ESAPI encodeForHTML带有一些允许的格式化标签

时间:2013-06-30 16:08:16

标签: php html security owasp esapi

在Web项目中,我们使用PHP中的OWASP ESAPI进行输出编码。在某些时候,我们希望允许HTML的子集用于少量格式化选项(例如,<i><b>),同时禁止所有其他标记和特殊字符(因此它们是实体编码的)使用&...;语法)。

我认为有以下几种可能性来实现这一目标:

  1. 告诉the OWASP ESAPI encoder白名单/允许这些标记,以便它只对所有其他HTML标记和实体进行正确编码。但这似乎并不受支持。然而,我们可能(也许)写一个允许这个的补丁。
  2. 使用ESAPI进行编码后解码列入白名单的标记。这会被攻击吗?
  3. 对此用例使用其他一些输出编码技术。还有其他图书馆吗?
  4. 特别是,我需要将以下标记和属性列入白名单:

    • <br>
    • <i>
    • <b>
    • <u>
    • <big>
    • <small>
    • <sub>
    • <sup>
    • <font color="...">
    • <ul> + <li>
    • <ol> + <li>

    请注意,我们的应用程序对安全至关重要。这意味着我们要实现的任何方法都应该只接受上面的标记(可能还有一些格式化的标记),其他一切都必须正确地进行实体编码。通过查看代码的(简单)代码/解释,毫无疑问,这应该是容易验证的。代码越短,评论越容易。完全手工编制的编码器并不适合这种情况。

3 个答案:

答案 0 :(得分:2)

听起来你正在寻找的是HTMLPurifier

http://htmlpurifier.org/

FWIW我根本不隶属于HTMLPurifier,而且我是OWASP ESAPI项目的项目负责人。

答案 1 :(得分:0)

在过去我曾参与过的几个项目中,我使用Codeigniter安全类作为实现我自己的安全功能的指南。

在这里查看GitHub上的来源:https://github.com/EllisLab/CodeIgniter/blob/develop/system/core/Security.php

此代码中有几个与encoding和xss相关的部分。可能对您的情况有用。

答案 2 :(得分:-1)

查看下面的代码,在PHP 5.3上测试,运行正常。代码评论已添加。

<?php

// test input data
$data = 'br1<br>,br3<br >,      br4<br/>,br2<br />, <i>i1</i><b>b1</b> foo<b onmouseover="alert(hi);">b1</b><u tricky="hello">u1</u> <big>big1</big><small>small1</small> <sub>sub1</sub><div name="aaaa">div1</div> <sup>sup1</sup><font>font1</font> <font       >font2</font><font onmouseover="alert(\'hi\');"  color="red" style="background-color:green;">font3</font><font onmouseover="alert(\'hi\');"  color="red" style="background-color:green;" >font4</font><ul><li>li1</li></ul><ol><li>li2</li></ol>';

// set the allowed tags and their allowed attribs
// case-insensitive
$allowed = array(
"br" => "", // second value is allowed attrs, "" means all attrs allowed for this tag
"i" => "",
"b" => "",
"u" => "",
"big" => "",
"small" => "",
"sub" => "",
"sup" => "",
"font" => "color,style", // comma separated list of allowed attrs, other attrs will be stripped out
"ul" => "",
"ol" => "",
"li" => "",
);

// this will contain output results
$outdata='';
// this func will do the job
fixit();
// print out the results
echo $outdata;

function start_element_handler($parser, $name, $attrs) {
    global $outdata,$allowed;
    // tag allowed, check further
    if( in_array($name,array_keys($allowed)) ) {
        $attrout="";
        if(!empty($attrs)) {
            foreach($attrs as $attr=>$val) {
                // attr allowed, write normal output, else skip the attr/val
                if(empty($allowed[$name]) || in_array($attr,$allowed[$name]))
                    $attrout=$attrout." ".strtolower($attr)."=\"$val\" ";
            }
        }
        $outdata=$outdata."<".strtolower($name)."$attrout>";
    }
    // tag not allowed, htmlentityencode the output
    else {
        $attrout="";
        if(!empty($attrs)) {
            foreach($attrs as $attr=>$val) {
                $attrout=$attrout." ".strtolower($attr)."=\"$val\" ";
            }
        }
        $outdata=$outdata.htmlentities("<".strtolower($name)."$attrout>",ENT_COMPAT,'UTF-8');
    }
}

function end_element_handler($parser, $name) {
    global $outdata,$allowed;
    // void elements have no ending tags, so skip writing to output
    $voids = array("AREA", "BASE", "BR", "COL", "COMMAND", "EMBED", "HR", "IMG", "INPUT", "KEYGEN", "LINK", "META", "PARAM", "SOURCE", "TRACK", "WBR");
    if(in_array($name,$voids))
        return;
    $nameout = "</".strtolower($name).">";
    // tag allowed, write normal output
    if( in_array($name,array_keys($allowed)) ) {
        $outdata=$outdata.$nameout;
    }
    // tag not allowed, htmlentityencode the output 
    else {
        $outdata=$outdata.htmlentities($nameout,ENT_COMPAT,'UTF-8');
    }
}

function default_handler($parser, $data) {
    global $outdata,$allowed; $outdata=$outdata.htmlentities($data,ENT_COMPAT,'UTF-8');
}

function fixit() {
    global $data, $allowed, $outdata;
    $outdata="";
    // added temp body tags to make xml parser work fine  
    $data="<body>{$data}</body>";
    // change allowed tags and attrs to uppercase for comparisons later
    $allowed=array_change_key_case($allowed,CASE_UPPER);
    foreach($allowed as $tag=>$attrs) $allowed[$tag] = array_filter(explode(",",strtoupper($attrs)));
    // create the parser
    $parser = xml_parser_create('UTF-8');
    // set to uppercase comparisons
    xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
    xml_set_element_handler($parser, 'start_element_handler', 'end_element_handler');
    xml_set_default_handler($parser, 'default_handler');
    // parse the data 
    xml_parse($parser, $data, true);
    xml_parser_free($parser);
    // set output in $outdata variable
    $outdata = str_ireplace(array('&lt;body&gt;','&lt;/body&gt;'), "", $outdata); 
}

?>