我有一个 PHP 网页,它使用 URL 参数来设置一个变量,然后该变量显示在该页面中。 网址:webaddress.com/page.php?id=someCity
我们采用 $_GET['id'] 并将其分配为变量 ($city),然后在页面上使用该变量以某种动态方法重建静态文本。
例如:
欢迎来到我们关于Somecity的页面。我们可以帮助您找到与someCity相关的产品,因为我们在Somecity方面拥有丰富的经验。显然,这可以使用
<?php echo $city; ?>
来实现
我的客户被告知他对跨站脚本 (XSS) 漏洞持开放态度。我的研究表明,iFrame 可用于窃取 cookie 并执行恶意操作。推荐的解决方案是使用 PHP 函数 htmlspecialchars() 将字符更改为“HTML 实体”。我不明白这比使用 strip_tags() 简单地删除所有标签更安全。
因此,我同时使用两者以及字符串替换和大写,因为这也是需要的。
$step1 = str_replace('_', ' ', $_GET['id']); // Remove underline replace with space
$step2 = strip_tags($step1); // Strip tags
$step3 = htmlspecialchars($step2); // Change tag characters to HTML entities
$city = ucwords($step3);
问题:这是否足以防止 XSS?htmlspecialchars() 是否比 strip_tags() 有额外的好处? 我根据其他提交的类似问题了解差异,但想知道每个函数(尤其是 htmlspecialchars() )如何防止 XSS。
这是 OWASP XSS 预防备忘单 (https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html) 中的规则 1。
这里,建议对
&
、<
、>
、'
、"
、/
等特殊字符进行编码。除了正斜杠(这对于编码来说并不是严格必要的)之外,这就是函数 htmlspecialchars
或 htmlentities
所做的事情。
之前运行
strip_tags
的唯一区别是,不是将 <
编码为 <
,将 >
编码为 >
,而是将它们以及它们之间的其他内容从字符串中删除。这并没有提供更多的安全性,因为字符串 <
在这种情况下与空字符串一样安全。它的缺点是会破坏有效输入,因为 <
和 >
可能出现在普通文本中,因此不能一致地用作输出编码策略。
此外,对于 HTMLPurifier,这在这里不合适,因为目的是将 HTML 输入转换为 HTML 输出,但您有纯文本输入而不是 HTML。 HTMLPurifier 将保持城市名称
<b>Somecity</b>
不变,并且根本不进行任何编码。这可能是安全的,因为它不能包含脚本,但不适合在此处允许任何 HTML 格式更改,并且应该提前编码或拒绝作为无效输入。
最好的方法是使用成熟且值得信赖的库,例如 HTMLPruifier 来清理来自不受信任来源的任何内容。仅仅运行 strip_tags 是不够的,那里有很多创造性和阴险的 XSS 攻击。我建议您查看OWASP 建议,以缓解 XSS。值得花时间小心这种事情并在开发过程中实际测试漏洞。
如果您对此不熟悉,我认为还值得研究一些白帽捕获标志风格的信息安全培训(有大量可用的免费资源),以便您了解此类攻击如何在真实世界。看到他们能变得多么聪明,真是令人大开眼界。
strip_tags()
仅删除标签,但不删除其他特殊字符。另一方面,htmlspecialchars()
将 HTML 中具有特殊意义的字符视为 HTML 实体。您可以在此处找到更多信息。
一般来说,
htmlspecialchars()
就足够了。如果您想允许某些标签,您应该使用库 HTMLPurifier,正如 Rob Ruchte 建议的那样。
我相信在所提供的情况下最好的答案是使用这两个函数。首先使用 strip_tags() 去除所有标签,然后使用 htmlspecialchars() 对剩余的情况进行排序。上面提供了顺序。
对于已知的字符串列表(不是非结构化文本),您可以使用如下方法:
$city= $_GET['city'];
$checkCity = array("New York", "Paris", "London"); // Add Cities as needed
$city= in_array($city, $checkCity) ? $city: "none";
它检查数组中的字符串,如果找到则返回城市名称,否则不返回。这可以防止页面上出现 URL 的任何欺骗行为。