关键要点
跨站脚本攻击是互联网上每天发生的五大安全攻击之一,您的 PHP 脚本也可能无法幸免。这种攻击也称为 XSS,它基本上是一种代码注入攻击,由于用户数据验证不正确而成为可能,这些数据通常通过 Web 表单或使用更改后的超链接插入到页面中。注入的代码可以是任何恶意的客户端代码,例如 JavaScript、VBScript、HTML、CSS、Flash 等。该代码用于在服务器上保存有害数据或在用户的浏览器中执行恶意操作。不幸的是,跨站脚本攻击主要发生是因为开发人员未能提供安全的代码。每个 PHP 程序员都有责任了解如何对他们的 PHP 脚本进行攻击以利用可能的安全漏洞。阅读本文,您将了解有关跨站脚本攻击的更多信息以及如何在您的代码中防止它们。
通过示例学习
让我们来看下面的代码片段。
<code class="language-php"><form action="post.php" method="post"> <input type="text" name="comment" value=""> <input type="submit" name="submit" value="Submit"> </form></code>
这里我们有一个简单的表单,其中有一个文本框用于数据输入和一个提交按钮。提交表单后,它将提交数据到 post.php 进行处理。假设 post.php 只输出数据,如下所示:
<code class="language-php"><?php echo $_POST["comment"]; ?></code>
没有任何过滤,黑客可以通过表单提交以下内容,这将在浏览器中生成一个带有消息“hacked”的弹出窗口。
<code class="language-javascript">alert("hacked")</code>
这个例子,尽管本质上是恶意的,但似乎并没有造成太大危害。但是,想想如果 JavaScript 代码被编写为窃取用户的 cookie 并从中提取敏感信息会发生什么?有比简单的 alert() 调用更糟糕的 XSS 攻击。
跨站脚本攻击可以分为两大类,基于它们传递恶意有效负载的方式:非持久性 XSS 和持久性 XSS。请允许我详细讨论每种类型。
也称为反射型 XSS 攻击,这意味着恶意代码实际上并未存储在服务器上,而是通过服务器传递并呈现给受害者,这是两种传递方法中更流行的 XSS 策略。攻击是从外部来源发起的,例如电子邮件或第三方网站。这是一个简单的搜索结果脚本的一部分示例:
<code class="language-php"><form action="post.php" method="post"> <input type="text" name="comment" value=""> <input type="submit" name="submit" value="Submit"> </form></code>
此示例可能是一个非常不安全的成果页面,其中搜索查询会显示回用户。这里的问题是,$_GET["query"]
变量未经验证或转义,因此攻击者可以向受害者发送以下链接:
<code class="language-php"><?php echo $_POST["comment"]; ?></code>
无需验证,页面将包含:
<code class="language-javascript">alert("hacked")</code>
当恶意代码已经通过验证过程并存储在数据存储中时,就会发生这种类型的攻击。这可能是评论、日志文件、通知消息或网站上任何其他需要用户输入的部分。稍后,当此特定信息显示在网站上时,恶意代码就会执行。让我们使用以下示例来创建一个基本的基于文件的评论系统。假设我前面介绍的相同表单,假设接收脚本只是将评论附加到数据文件。
<code class="language-php"><?php // 根据查询获取搜索结果 echo "You searched for: " . $_GET["query"]; // 列出搜索结果 ...</code>
在其他地方,comments.txt 的内容显示给访问者:
<code>http://example.com/search.php?query=alert("hacked")</code>
当用户提交评论时,它会被保存到数据文件中。然后,整个文件(因此是整个评论系列)将显示给读者。如果提交了恶意代码,则它将被保存并按原样显示,没有任何验证或转义。
防止跨站脚本攻击
幸运的是,与对不受保护的网站进行 XSS 攻击一样容易,防止它们也同样容易。但是,即使在编写一行代码之前,预防也必须始终铭记在心。任何 Web 环境(无论是开发、暂存还是生产)都需要“强制执行”的第一条规则是永远不要信任来自用户或任何其他第三方来源的数据。这怎么强调都不为过。必须验证每一位数据输入,并在输出时进行转义。这是防止 XSS 的黄金法则。为了实施防止 XSS 攻击的可靠安全措施,我们应该注意数据验证、数据清理和输出转义。
数据验证是确保应用程序使用正确数据运行的过程。如果您的 PHP 脚本期望用户输入整数,则任何其他类型的数据都将被丢弃。接收到的每条用户数据都必须经过验证,以确保其类型正确,如果未通过验证过程,则将其丢弃。例如,如果您想验证电话号码,您将丢弃包含字母的任何字符串,因为电话号码应仅包含数字。您还应考虑字符串的长度。如果您想更宽松一些,您可以允许有限的一组特殊字符,例如加号、括号和破折号,这些字符通常用于格式化特定于您目标区域设置的电话号码。
<code class="language-php"><form action="post.php" method="post"> <input type="text" name="comment" value=""> <input type="submit" name="submit" value="Submit"> </form></code>
数据清理侧重于操作数据以确保其安全,方法是从数据中删除任何不需要的位并将其规范化为正确的形式。例如,如果您期望纯文本字符串作为用户输入,您可能希望从中删除任何 HTML 标记。
<code class="language-php"><?php echo $_POST["comment"]; ?></code>
有时,数据验证和清理/规范化可以同时进行。
<code class="language-javascript">alert("hacked")</code>
为了保护显示/输出数据的完整性,您应该在将数据呈现给用户时对其进行转义。这可以防止浏览器对可能找到的任何特殊字符序列应用任何意外的含义。
<code class="language-php"><?php // 根据查询获取搜索结果 echo "You searched for: " . $_GET["query"]; // 列出搜索结果 ...</code>
现在一起!
为了更好地理解数据处理的三个方面,让我们再次查看前面基于文件的评论系统,并对其进行修改以确保其安全。代码中的潜在漏洞源于这样一个事实,即 $_POST["comment"]
被盲目地附加到 comments.txt 文件中,然后直接显示给用户。为了确保其安全,应在将 $_POST["comment"]
值添加到文件之前对其进行验证和清理,并且在将文件内容显示给用户时应对其进行转义。
<code>http://example.com/search.php?query=alert("hacked")</code>
该脚本首先验证传入的评论,以确保用户已提供非零长度字符串。毕竟,空白评论不是很有趣。数据验证需要在一个定义良好的上下文中进行,这意味着如果我期望从用户那里获得一个整数,那么我会通过将数据转换为整数并将其作为整数处理来相应地对其进行验证。如果这导致无效数据,则只需将其丢弃并让用户知道。然后,脚本通过删除可能包含的任何 HTML 标记来清理评论。最后,检索、过滤和显示评论。通常,htmlspecialchars()
函数足以过滤打算在浏览器中查看的输出。但是,如果您在网页中使用的字符编码不是 ISO-8859-1 或 UTF-8,那么您可能需要使用 htmlentities()
。有关这两个函数的更多信息,请阅读官方 PHP 文档中的各自说明。请记住,在像 Web 这样不断发展的媒介上,不存在 100% 安全的单一解决方案。使用最新的 XSS 测试向量彻底测试您的验证代码。使用以下来源的测试数据应该可以揭示您的代码是否仍然容易受到 XSS 攻击。
总结
希望本文对您很好地解释了跨站脚本攻击是什么以及如何防止它们发生在您的代码中。永远不要信任来自用户或任何其他第三方来源的数据。您可以通过在一个定义良好的上下文中验证传入的值、清理数据以保护您的代码以及转义输出以保护您的用户来保护自己。编写代码后,请确保您的工作正常,方法是尽可能彻底地测试代码。
(图片来自 Inge Schepers / Shutterstock)
如果喜欢这篇文章,您会喜欢 Learnable;从大师那里学习新技能和技巧的地方。会员可以立即访问所有 SitePoint 的电子书和交互式在线课程,例如 Jump Start PHP。
本文的评论已关闭。对 PHP 有疑问?为什么不在我们的论坛上提问呢?
关于 PHP 安全性和跨站脚本攻击 (XSS) 的常见问题 (FAQ)
跨站脚本 (XSS) 攻击会对 PHP 应用程序产生重大影响。它们可能导致数据盗窃、会话劫持、网站损毁,甚至将恶意代码分发给用户。XSS 攻击利用 Web 应用程序中的漏洞来注入恶意脚本,然后由用户的浏览器执行。这可能会危及用户与应用程序的交互,并可能泄露敏感信息。
识别 PHP 应用程序中潜在的 XSS 漏洞需要结合手动代码审查和自动化测试。查找代码中用户输入直接包含在输出中而没有适当清理或验证的区域。像 XSS 扫描器这样的自动化工具还可以通过测试各种 XSS 攻击向量来帮助识别潜在的漏洞。
XSS 攻击通常涉及将恶意脚本注入其他用户查看的网页。这可以通过多种方法完成,例如将脚本嵌入 URL 参数、表单输入甚至 cookie 中。然后,恶意脚本可以代表用户执行操作,例如窃取其会话 cookie 或操作网页内容。
防止 PHP 应用程序中的 XSS 攻击涉及验证和清理用户输入、编码输出以及使用适当的 HTTP 标头。始终将用户输入视为不受信任,并根据可接受值的允许列表对其进行验证。清理输入以删除任何可能存在危害的字符或代码。编码输出以确保任何可能存在危害的字符都变得无害。使用 HTTP 标头(如内容安全策略)来限制脚本和其他资源的来源。
内容安全策略 (CSP) HTTP 标头在防止 XSS 攻击中起着至关重要的作用。它允许您指定浏览器应认为是可执行脚本有效来源的域。这意味着,即使攻击者可以将脚本注入您的网页,浏览器也不会运行它,除非脚本的来源在您的 CSP 中列入白名单。
存储型 XSS 攻击涉及注入永久存储在目标服务器上的恶意脚本。然后,当用户查看某些页面时,脚本就会提供给用户。另一方面,反射型 XSS 攻击涉及通过 URL 或表单输入注入脚本,然后服务器立即在响应中返回该脚本并由用户的浏览器执行。
PHP 提供了一些内置函数,可以帮助防止 XSS 攻击。例如,htmlspecialchars()
函数可用于编码用户输入中的特殊字符,从而使潜在的脚本无害。filter_input()
函数可用于清理用户输入,删除或编码有害字符。
HTTPOnly Cookie 是一种无法通过客户端脚本访问的 Cookie。这意味着,即使攻击者可以将脚本注入您的网页,他们也无法使用该脚本读取或修改 HTTPOnly Cookie。这可以帮助保护敏感信息(例如会话标识符)不被 XSS 攻击窃取。
是的,XSS 攻击可能会用来绕过跨站点请求伪造 (CSRF) 保护。如果攻击者可以将脚本注入您的网页,他们可以使用该脚本代表用户执行操作,从而可能绕过您已实施的任何 CSRF 保护。这就是为什么保护免受 XSS 和 CSRF 攻击都很重要的原因。
是的,许多 PHP 框架都提供针对 XSS 攻击的内置保护。例如,Laravel 会自动编码输出以防止 XSS 攻击。其他框架(如 Symfony 和 CodeIgniter)也提供用于清理用户输入和编码输出的功能。但是,必须记住,没有哪个框架可以提供完全的保护,您仍然应该遵循防止 XSS 攻击的最佳实践。
以上是跨站点脚本攻击(XSS)的详细内容。更多信息请关注PHP中文网其他相关文章!