0

我想删除所有事件属性(例如,从基于事件参考列表的所有事件中)。

PHP 的 DOMDocument 类中是否有识别事件属性的函数?

我尝试使用 RegEx,但单引号和双引号变得复杂:

preg_replace('/on*[a-z]+=".*?"/i', '', $html); // Doesn't match onclick="alert(\"hello\");"

我尝试了一个名为 HTMLPurifier 的外部库,但它没有删除所有事件属性的选项。

知道要采取什么方向或简单的解决方案吗?

4

4 回答 4

1

如果您想要真正安全的代码,白名单方法(“只允许这些事情:...”)通常比黑名单方法(“不允许这些事情:...”)更可靠。

您提到了 HTML Purifier 并且“它没有删除所有事件属性的选项”。

那是...在技术上是正确的,因为您不能告诉它删除事件属性。不过,原因在于卖点:它会自动执行此操作。“缺少”的选项是配置 HTML Purifier 以允许事件属性的能力。这是故意的不对。HTML Purifier(顾名思义)具有很强的安全性。

可以使用 HTML Purifier 配置允许一些“不安全的 HTML”方面(默认配置是故意挑剔的),但事件属性不在其中。(好吧,如果你跳过圈子,你可以教 HTML Purifier 接受它们,但这需要付出很多努力。)

如果您想接受用户 HTML,我建议您再试一次。这是一个相当成熟的工具,已经过很多人的测试。

有一些非常棘手的方法可以破坏 HTML 并注入 JavaScript。例如,您是否知道可以使用srcorhref属性注入 JavaScript?你知道你可以在某些浏览器中使用style标签注入 JavaScript 吗?看看这个 XSS 备忘单。它可能会让您大致了解您所面临的问题,以及为什么通常认为白名单更有效。

不管怎样,祝你好运!

于 2013-06-24T20:48:10.633 回答
1
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>');
于 2021-01-28T06:36:01.457 回答
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);
于 2013-06-24T05:32:23.707 回答
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);
        }
    }
}

您可能还想抓取已知属性名称列表,并在发现未知属性名称时发出警告(或拥有您允许的属性白名单)。希望这会有所帮助,快速键入代码可能会出现一些小错误。

于 2013-06-24T07:38:27.567 回答