strip_tags() 是否容易受到脚本攻击?

2022-08-30 10:11:58

是否有已知的 XSS 或其他攻击使其通过

$content = "some HTML code";
$content = strip_tags($content);

echo $content;

?

手册中有一个警告:

此函数不会修改您允许使用allowable_tags的标记上的任何属性,包括恶作剧用户在发布将向其他用户显示的文本时可能滥用的样式和 onmouseover 属性。

但这与仅使用参数有关。allowable_tags

没有设置允许的标签,是否容易受到任何攻击?strip_tags()

Chris Shiflett似乎说这是安全的:

使用成熟的解决方案

如果可能,请使用成熟的现有解决方案,而不是尝试创建自己的解决方案。像strip_tags()和htmlentities()这样的函数是不错的选择。

这是正确的吗?如果可能的话,请引用来源。

我知道HTML净化器,htmlspecialchars()等 - 我不是在寻找清理HTML的最佳方法。我只想知道这个具体问题。这是一个理论问题,在这里出现。

参考:PHP 源代码中的 strip_tags() 实现


答案 1

顾名思义,应该删除所有HTML标签。我们证明它的唯一方法是分析源代码。下一个分析适用于调用,没有白名单标签的第二个参数。strip_tagsstrip_tags('...')

首先,关于HTML标签的一些理论:标签以一个开头,后跟非空格字符。如果此字符串以 开头,则不应对其进行解析。如果此字符串以 开头,则将其视为注释,并且不应解析以下文本。注释以 在此类注释中,字符 like 和 是允许的,以 终止。属性可以出现在标记中,其值可以选择用引号字符( 或 )括起来。如果存在这样的引号,则必须将其关闭,否则如果遇到 a,则不会关闭标记。<?!----><>'">

该代码在 Firefox 中解释为:<a href="example>xxx</a><a href="second">text</a>

<a href="http://example.com%3Exxx%3C/a%3E%3Ca%20href=" second"="">text</a>

php 函数strip_tagsext/standard/string.c 的第 4036 行中引用。该函数调用内部函数php_strip_tags_ex

存在两个缓冲区,一个用于输出,另一个用于“内部 HTML 标记”。名为 的计数器保存左尖括号 () 的数目。
该变量包含引号字符 ( or ) (如果有),否则。最后一个字符存储在变量 中。depth<in_q'"0lc

这些函数具有五种状态,其中三种在函数上面的描述中提到。基于此信息和函数体,可以推导出以下状态:

  • 状态 0 是输出状态(不在任何标记中)
  • 状态 1 表示我们位于正常的 html 标记中(标记缓冲区包含<)
  • 状态 2 表示我们在 php 标记内
  • 状态 3:我们从输出状态出来,遇到了 和 字符 (标签缓冲区包含<!<!)
  • 状态 4:在 HTML 注释内

我们只需要小心,不能插入任何标签。也就是说,后跟一个非空格字符。第 4326 行检查字符的大小写,如下所述:<<

  • 如果在引号内(例如),则忽略该字符(从输出中删除)。<a href="inside quotes"><
  • 如果下一个字符是空格字符,则<将添加到输出缓冲区
  • 如果在 HTML 标记之外,则状态变为(“在 HTML 标记内”),并且最后一个字符设置为1lc<
  • 否则,如果在 HTML 标记内,则 named 的计数器将递增,并忽略该字符。depth

如果在标记打开时满足 ,则变为(“不在引号中”)和变为(“不在标记中”)。标记缓冲区将被丢弃。>state == 1in_q0state0

属性检查(对于像 和 这样的字符)在被丢弃的标记缓冲区上完成。所以结论是:'"

strip_tags没有标签白名单可以安全地包含在标签之外,则不允许使用任何标签。

通过“外部标签”,我的意思是不像在标签中那样。文本可能包含 和,如 中所示。结果不是有效的 HTML,但 ,仍然需要转义,尤其是 .这可以用htmlspecialchars()来完成<a href="in tag">outside tag</a><>>< a>><>&&

没有白名单参数的描述是:strip_tags

确保返回的字符串中不存在 HTML 标记。


答案 2

我无法预测未来的漏洞利用,特别是因为我还没有看过PHP源代码。但是,由于浏览器接受看似无效的标记(如 ),过去曾有过漏洞利用。因此,将来有人可能会利用奇怪的浏览器行为。<s\0cript>

除此之外,将输出作为完整的HTML块直接发送到浏览器应该永远不会不安全:

echo '<div>'.strip_tags($foo).'</div>'

但是,这并不安全:

echo '<input value="'.strip_tags($foo).'" />';

因为可以通过并插入脚本处理程序轻松结束报价。"

我认为总是将stray转换为(引号也是如此)要安全得多。<&lt;


推荐