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

Is strip_tags() vulnerable to scripting attacks?

提问人:Pekka 提问时间:4/26/2011 最后编辑:CommunityPekka 更新时间:5/9/2023 访问量:25003

问:

是否存在已知的 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() 实现

php html 安全 xss strip-tags

评论

1赞 Damon 4/26/2011
好吧,没有给出任何参数,它去除了所有标签,所以我看不出怎么会有任何漏洞。最糟糕的情况是有人给你提供无效的标记(没有结束标签),但这种最坏的情况只是意味着会剥离更多的文本。strip_tags
0赞 Pekka 4/26/2011
@Gordon谢谢,但我的意思是只有一整块 HTML 数据,所以没有注入的文件名等(如果我理解正确的话,这就是论坛条目正在讨论的内容。 据我所知,该线程并未证明 strip_tags() 中的漏洞,但继续推荐 htmlspecialchars() - 这也是我通常做的, 但我想知道这是否真的有必要
4赞 mario 4/26/2011
htmlpurifier.org/comparison#striptags 有点不屑一顾。这可能不言而喻,但对于新来者来说需要重复一遍:条带标签是否安全取决于上下文。如果输出以属性结尾,则为否。只有当剥离的内容进入页面正文时,才可以。(为此,这确实足够了。
1赞 Gordon 4/26/2011
@Pekka packetstormsecurity.org/search/?q=strip_tags
1赞 Sumit 8/1/2016
更新了实现链接: github.com/php/php-src/blob/master/ext/standard/string.c#L4729strip_tags()

答:

1赞 kemus 4/26/2011 #1

剥离标签是完全安全的 - 如果您所做的只是将文本输出到 html 正文。

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

评论

0赞 Obsidian Age 7/27/2021
虽然这个答案已经有 10 年的历史了,但值得一提的是,如果你像我一样在 2021 年偶然发现这个答案——这个答案是完全不真实的,而且是彻头彻尾的危险信息。
54赞 Lekensteyn 4/27/2011 #2

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

首先,关于HTML标签的一些理论:标签以a开头,后跟非空格字符。如果此字符串以 开头,则不应对其进行解析。如果此字符串以 开头,则将其视为注释,并且不应解析以下文本。注释以 结尾,在此类注释中,允许使用 和 等字符。属性可以出现在标记中,它们的值可以选择用引号字符(或 )括起来。如果存在这样的引号,则必须将其关闭,否则如果遇到 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 标记”。名为 的计数器保存左尖括号 () 的数目。
该变量包含引号字符(或 ),如果有,否则。最后一个字符存储在变量 中。
depth<in_q'"0lc

函数包含五种状态,其中三种在函数上方的描述中提到。基于此信息和函数体,可以派生出以下状态:

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

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

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

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

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

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

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

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

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

评论

16赞 rinogo 2/10/2017
所以。。。顶级域名;- 是的,安全吗?strip_tags()
0赞 bishop 9/17/2020
@rinogo 是的,当仅使用一个参数调用时是安全的。strip_tags
11赞 Matthew 4/27/2011 #3

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

撇开这一点不谈,将输出作为完整的 HTML 块直接发送到浏览器应该永远不会不安全:

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

但是,这并不安全:

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

因为可以很容易地通过并插入脚本处理程序来结束引用。"

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

7赞 Ludovico Grossi 11/3/2017 #4

根据这个在线工具,这个字符串将被“完美”转义,但是 结果是另一个恶意的!

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

在字符串中,“真实”标签是 和 ,因为 和 单独不是标签。<a></a><script>

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

评论

3赞 luckydonald 3/3/2018
var_dump(strip_tags("<<a>script>alert('ciao');<</a>/script>")); => "alert('ciao');"在 PHP 7.1.2 中。它似乎在遇到 an 之后删除了所有内容。<>
0赞 Darragh Enright 2/4/2019
哦,这太讨厌了。不过,似乎通过了这里的所有测试:3v4l.org/BBapp#output
0赞 Antony 7/18/2022
值得一提的是,在 PHP 8 中,这现在只会导致alert('ciao');
0赞 Christiaan 4/11/2023
此处引用的工具使用 JavaScript 来解析字符串,因此不能很好地表示问题。
3赞 Obsidian Age 7/27/2021 #5

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

易受攻击的原因是它不递归运行。也就是说,它不会检查在去除有效标签后是否还会保留有效标签。例如,字符串
将成功剥离标签,但看不到此离开
strip_tags()<<a>script>alert(XSS);<</a>/script><a><script>alert(XSS);</script>

这可以在这里(在安全的环境中)看到。

评论

0赞 iSWORD 11/8/2021
但我想如果它在通过后发生变化,仍然可以使用它来完全拒绝用户输入,对吧?strip_tags
1赞 Antony 7/18/2022
值得一提的是,在 PHP 8 中,这现在只会导致alert('XSS');
-1赞 igraczech 5/5/2023 #6

我刚刚能够在 href 中注入脚本 pn PHP 8:strip_tags()

测试使用:

<a href="javascript:alert(1)">Click me!</a>

显然,这需要用户交互,但通过此功能。

类似于 strip_tags() 是否容易受到脚本攻击?但没有额外的插入符号。

评论

0赞 Your Common Sense 5/5/2023
这里已经提到过