我想删除所有事件属性(例如,基于Event reference list的所有事件)。
PHP的DOMDocument类中是否有识别事件属性的函数?
我尝试过使用RegEx但是单引号和双引号变得复杂了:
preg_replace('/on*[a-z]+=".*?"/i', '', $html); // Doesn't match onclick="alert(\"hello\");"
我尝试了一个名为HTMLPurifier的外部库,但它没有删除所有事件属性的选项。
知道要采取什么方向或简单的解决方案?
答案 0 :(得分:1)
如果你想要真正安全的代码,白名单方法('只允许这些东西:......')通常比黑名单方法更坚固('不允许这些事情:......')。
您提到了HTML Purifier,并且“它没有删除所有事件属性的选项”。
这是......技术上正确,因为你不能告诉它删除事件属性。原因是卖点:它会自动完成。 “缺失”选项是将HTML Purifier配置为允许事件属性的功能。这是故意的错。 HTML Purifier(顾名思义)具有很强的安全性。
你可以允许使用HTML Purifier配置的一些'不安全的HTML'方面(默认配置是故意挑剔的),但事件属性不在那些。 (好吧,你可以教HTML HTML Purifier接受它们,如果你跳过篮球,但需要付出很多努力。)
如果您想接受用户HTML,我建议您再试一次。这是一个相当成熟的工具,已经过很多人的测试。
有一些非常棘手的方法可以破解HTML并注入JavaScript。例如,您是否知道可以使用src
或href
属性注入JavaScript?您是否知道在某些浏览器中,您可以使用style
标记注入JavaScript?看看this XSS cheatsheet。它可能会让您大致了解您的反对意见,以及为什么白名单通常被认为更有效。
无论哪种方式,祝你好运!
答案 1 :(得分:0)
使用DOM制作它的方法。
以下代码在所有html标记中查找并删除名称以“on”开头的属性。
($html
代表html代码)
$doc = new DOMDocument();
@$doc->loadHTML($html);
$xpath = new DOMXPath($doc);
$onAttributes = $xpath->query("//*/@*[starts-with(name(), 'on')]");
foreach ($onAttributes as $onAttribute) {
$onAttribute->ownerElement->removeAttributeNode($onAttribute);
}
$body = $xpath->query('body')->item(0);
$result = substr($doc->saveHTML($body),6,-7);
答案 2 :(得分:0)
加载HTML文档,遍历所有元素,然后遍历它们的所有属性(嵌套),如果它们以on
开头,则删除属性:
$doc = new DOMDocument();
$doc->loadHTML($html);
foreach ($doc->getElementsByTagname('*') as $element)
{
foreach (iterator_to_array($element->attributes) as $name => $attribute)
{
if (substr_compare($name, 'on', 0, 2, TRUE) === 0)
{
$element->removeAttribute($name);
}
}
}
您还可能需要抓取已知属性名称列表,并在找到未知属性名称时给出警告(或者您具有允许的属性列表)。希望这会有所帮助,快速输入代码可能会有一些小错误。
答案 3 :(得分:0)
function filterText($value)
{
if(!$value) return $value;
return escapeJsEvent(removeScriptTag($value));
}
function escapeJsEvent($value){
return preg_replace('/(<.+?)(?<=\s)on[a-z]+\s*=\s*(?:([\'"])(?!\2).+?\2|(?:\S+?\(.*?\)(?=[\s>])))(.*?>)/i', "$1 $3", $value);
}
function removeScriptTag($text)
{
$search = array("'<script[^>]*?>.*?</script>'si",
"'<iframe[^>]*?>.*?</iframe>'si");
$replace = array('','');
$text = preg_replace($search, $replace, $text);
return preg_replace_callback("'&#(\d+);'", function ($m) {
return chr($m[1]);
}, $text);
}
echo filterText('<img src=1 href=1 onerror="javascript:alert(1)"></img>');