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

时间:2011-04-26 09:40:15

标签: php html security xss strip-tags

是否有已知的XSS或其他攻击使其超越

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

echo $content;

manual有警告:

  

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

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

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

Chris Shiflett似乎说这是安全的:

  

使用成熟的解决方案

     

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

这是对的吗?请尽可能引用来源。

我知道HTML净化器,htmlspecialchars()等。我正在寻找消毒HTML的最佳方法。我只想知道这个具体问题。这是一个理论问题here

参考:strip_tags() implementation in the PHP source code

5 个答案:

答案 0 :(得分:48)

正如其名称所示,strip_tags应删除所有HTML标记。我们可以证明它的唯一方法是分析源代码。下一个分析适用于strip_tags('...')调用,没有白名单标记的第二个参数。

首先,关于HTML标签的一些理论:标签以<开头,后跟非空白字符。如果此字符串以?开头,则为should not be parsed。如果此字符串以!--开头,则将其视为注释,并且不应解析以下文本。评论以-->终止,在此类评论中,允许使用<>等字符。属性可以在标记中出现,其值可以选择由引号字符('")包围。如果存在这样的引用,则必须将其关闭,否则如果遇到>,则标记不会关闭。

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

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

strip_tags中引用了PHP函数line 4036 of ext/standard/string.c。该函数调用internal function php_strip_tags_ex

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

函数包含五个状态,在函数上面的描述中提到了三个。基于此信息和函数体,可以导出以下状态:

  • 状态0是输出状态(不在任何标记中)
  • 状态1表示我们位于普通的html标记内(标记缓冲区包含<
  • 状态2表示我们在php标签内
  • 状态3:我们来自输出状态并遇到<!个字符(标记缓冲区包含<!
  • 状态4:HTML评论

我们需要注意不要插入任何标签。也就是说,<后跟一个非空白字符。 Line 4326使用<字符检查案例,如下所述:

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

如果标签处于打开状态(>)时符合state == 1,则in_q变为0(“不在报价中”),state成为0(“不在标签中”)。 标记缓冲区被丢弃。

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

  

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

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

没有白名单参数的strip_tags说明如下:

  

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

答案 1 :(得分:10)

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

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

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

但是,这不安全:

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

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

我认为将流浪<转换为&lt;(和引号相同)会更安全。

答案 2 :(得分:3)

根据this online tool,这个字符串将是&#34;完美&#34;逃脱了,但是  结果是另一个恶意的!

<<a>script>alert('ciao');<</a>/script>

在字符串中&#34;真实&#34;标记为<a></a>,因为<script>都不是标记。

我希望我错了,或者仅仅是因为旧版本的PHP,但最好还是检查环境。

答案 3 :(得分:2)

剥离标签非常安全 - 如果您正在做的就是将文本输出到html正文。

将它放入mysql或url属性中并不一定安全。

答案 4 :(得分:1)

strip_tags() 容易受到脚本攻击,一直到(至少)PHP 8。不要用它来防止 XSS 。相反,您应该使用 filter_input()

strip_tags() 易受攻击的原因是它不会递归运行。也就是说,在有效标签被剥离后,它不会检查有效标签是否仍然存在。例如,字符串
<<a>script>alert(XSS);<</a>/script> 将成功剥离 <a> 标签,但看不到这个叶子
<script>alert(XSS);</script>

这可以看到(在安全环境中)here