54

是否存在已知的 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 的最佳方法。我只是想知道这个具体问题。这是这里提出的一个理论问题。

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

4

5 回答 5

53

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

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

该代码<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>

ext/standard/string.c 的第 4036 行strip_tags引用了PHP 函数。该函数调用内部函数 php_strip_tags_ex

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

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

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

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

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

如果在标签打​​开 ( )>时遇到,则变为("not in a quote") 并变为("not in a tag")。标记缓冲区被丢弃。state == 1in_q0state0

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

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

“外部标签”是指不在标签中,如在<a href="in tag">outside tag</a>. 文本可能包含<and >,如>< a>>. 结果不是有效的 HTML,但<仍需要转义,尤其>是. 这可以用.&&htmlspecialchars()

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

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

于 2011-04-26T16:35:12.857 回答
11

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

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

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

但是,这并不安全:

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

因为人们可以很容易地结束引用"并插入一个脚本处理程序。

我认为始终将杂散转换为(引号也一样)要安全<得多&lt;

于 2011-04-26T16:54:11.927 回答
7

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

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

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

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

于 2017-11-02T20:53:19.057 回答
2

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

放到mysql或者url属性中不一定安全。

于 2011-04-26T10:08:48.220 回答
2

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

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

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

于 2021-07-27T04:43:20.790 回答