在Web项目中,我们使用PHP中的OWASP ESAPI进行输出编码。在某些时候,我们希望允许HTML的子集用于少量格式化选项(例如,<i>
和<b>
),同时禁止所有其他标记和特殊字符(因此它们是实体编码的)使用&...;
语法)。
我认为有以下几种可能性来实现这一目标:
特别是,我需要将以下标记和属性列入白名单:
<br>
<i>
<b>
<u>
<big>
<small>
<sub>
<sup>
<font color="...">
<ul>
+ <li>
<ol>
+ <li>
请注意,我们的应用程序对安全至关重要。这意味着我们要实现的任何方法都应该只接受上面的标记(可能还有一些格式化的标记),其他一切都必须正确地进行实体编码。通过查看代码的(简单)代码/解释,毫无疑问,这应该是容易验证的。代码越短,评论越容易。完全手工编制的编码器并不适合这种情况。
答案 0 :(得分:2)
答案 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('<body>','</body>'), "", $outdata);
}
?>