2.13. 过滤 HTML 输入和输出

未匹配的标注

简单过滤使用 htmlentities() 函数,复杂过滤使用 HTML Purifier 库。

HTML Purifier 4.10.0 测试。

在任何 Web 应用程序中显示用户输入时,必须首先对其进行“清理”,以过滤任何潜在危险的 HTML。如果你的 Web 应用程序直接输出 HTML,恶意用户可以制作 HTML,对查看它的人造成威胁。

虽然使用正则表达式来过滤 HTML 可能很诱人,但不要这样做。HTML 是一种复杂的语言,几乎可以断定,任何使用正则表达式过滤 HTML 的尝试都会失败。

可能还有让你使用 strip_tags() 函数的建议。虽然 strip_tags() 在技术上是安全的,但它是一个“哑”函数,因为如果输入是无效的 HTML(例如,缺少一个结束标记),那么 strip_tags() 可能会删除比预期多得多的内容。因此,这也不是一个很好的选择,因为非技术用户在通信中经常使用 < 和 > 字符。

如果你阅读了有关 验证电子邮件地址 的部分,你可能还考虑使用 filter_var() 函数。但是, filter_var() 函数存在换行问题,需要复杂的配置来模拟 htmlentities() 函数。因此,这也不是一个好的选择。

对于简单过滤的需求

如果你的 Web 应用只需要完全转义(因此可以无害地呈现,但不是完全去除)HTML,请使用 PHP 内置的 htmlentities() 函数。这个函数比 HTML Purifier 快得多,因为它不在 HTML 上执行任何验证,仅转义所有东西。

htmlentities() 与功能相似的函数 htmlspecialchars() 不同,它会编码 所有 适用的 HTML 实体,而不仅仅是一小部分子集。

范例

<?php
// 哦,不!用户提交了恶意 HTML,我们不得不在 web 应用程序中显示它!
$evilHtml = '<div onclick="xss();">Mua-ha-ha!  Twiddling my evil mustache...</div>';

// 使用 ENT_QUOTES 标记确保单引号和双引号都做了转义。
// 如果你已经将文本存储为 UTF-8(你应该这样做),请使用 UTF-8 字符编码。
// 有关更多详细信息,请参阅本文档中的 UTF-8 部分。
$safeHtml = htmlentities($evilHtml, ENT_QUOTES, 'UTF-8'); // 你可以毫无顾虑地向用户输出 $safeHtml,它现在是完全转义好的 HTML!

对于复杂过滤的需求

对于许多 Web 应用程序来说,仅仅转义 HTML 是不够的。你可能希望完全删除所有 HTML,或者允许 HTML 的一小部分通过。为此,请使用 HTML Purifier 库。

HTML Purifier 是一个经过良好测试但速度较慢的库。如果你的需求没有那么复杂,就应该选用 htmlentities(),因为它会快得多。

HTML Purifier 与 strip_tags() 相比具有优势,因为它在净化 HTML 之前会对其校验。这意味着,如果用户输入了无效的 HTML,HTML Purifier 比 strip_tags() 更有可能保留 HTML 的预期含义。它还具有高度的可定制性,允许你将 HTML 的一个子集列入白名单以保留在输出中。

但其缺点就是相当的慢,它需要的一些设置,在共享主机环境中可能是不可行的,并且文档通常比较复杂和不容易理解。以下示例是基本配置。查看 文档 以了解 HTML Purifier 提供的更高级功能。

范例

<?php
// 引入 HTML Purifier 类库
require_once('htmlpurifier-4.6.0/HTMLPurifier.auto.php');

// 哦,不!用户提交了恶意 HTML,我们不得不在 Web 应用程序中显示它!
$evilHtml = '<div onclick="xss();">Mua-ha-ha!  Twiddling my evil mustache...</div>';

// 使用默认配置设置 HTML Purifier 对象。
$purifier = new HTMLPurifier(HTMLPurifier_Config::createDefault());

$safeHtml = $purifier->purify($evilHtml); // $safeHtml 现在已经做了过滤,可以毫无顾虑地向用户输出 $safeHtml!

要点

  • 与错误的字符编码一起使用可能会导致意外的输出。始终确保在调用函数时指定字符编码,并且该编码与正在清理的字符串的编码相匹配。有关更多详细信息,请参阅 UTF-8 章节 部分。
  • 使用 htmlentities() 时,始终包含 ENT_QUOTES 和字符编码参数。默认情况下,htmlentities() 不编码单引号。多么愚蠢的默认配置!
  • HTML Purifier 对于复杂的 HTML 来说速度非常慢。考虑设置一个缓存解决方案,比如 APCu 来存储过滤后的结果以供以后使用。

延伸阅读

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/phpbestpractice...

译文地址:https://learnku.com/docs/phpbestpractice...

上一篇 下一篇
贡献者:1
讨论数量: 0
发起讨论 只看当前版本


暂无话题~