【PortSwigger学院】跨站脚本(XSS)

跨站脚本

什么是跨站脚本 (XSS)?

跨站脚本攻击(又称 XSS)是一种网络安全漏洞,它允许攻击者破坏用户与有漏洞的应用程序之间的交互。它允许攻击者规避同源策略,该策略旨在将不同网站相互隔离。跨站脚本漏洞通常允许攻击者伪装成受害用户,执行用户能够执行的任何操作,并访问用户的任何数据。如果受害用户在应用程序中拥有特权访问权限,那么攻击者就可以完全控制应用程序的所有功能和数据。

XSS 如何工作?

跨站脚本攻击的原理是操纵有漏洞的网站,使其向用户返回恶意 JavaScript。当恶意代码在受害者的浏览器中执行时,攻击者就能完全破坏他们与应用程序的交互。

Labs

如果您已经熟悉了 XSS 漏洞背后的基本概念,只是想在一些现实的、故意易受攻击的目标上练习利用这些漏洞,您可以通过下面的链接访问本主题中的所有实验室。

XSS 概念验证

您可以通过注入有效负载,使自己的浏览器执行一些任意 JavaScript 来确认大多数类型的 XSS 漏洞。使用 alert() 函数来实现这一目的早已成为惯例,因为它简短、无害,而且成功调用时很难被忽略。事实上,我们的大多数 XSS 实验都是在模拟受害者的浏览器中调用 alert() 来解决的。

不幸的是,如果您使用的是 Chrome 浏览器,就会遇到一点小麻烦。从版本 92 开始(2021 年 7 月 20 日),跨源 iframe 无法调用 alert()。由于这些框架用于构建一些更高级的 XSS 攻击,因此有时需要使用其他 PoC 有效负载。在这种情况下,我们推荐使用 print() 函数。如果您有兴趣了解有关这一变更的更多信息,以及我们为什么喜欢 print(),请查看我们有关这一主题的博客

XSS 攻击有哪些类型?

XSS 攻击主要有三种类型。它们是:

  • 反射 XSS:恶意脚本来自当前 HTTP 请求。

  • 存储型 XSS:恶意脚本来自网站数据库。

  • 基于 DOM 的 XSS,即漏洞存在于客户端代码而非服务器端代码中

反射式跨站脚本

在本节中,我们将解释反射式跨站脚本,描述反射式 XSS 攻击的影响,并说明如何查找反射式 XSS 漏洞。

什么是反射式跨站脚本?

反射式 XSS 是跨站脚本攻击中最简单的一种。当应用程序接收 HTTP 请求中的数据,并以不安全的方式将这些数据包含在即时响应中时,就会出现这种情况。

下面是一个反射 XSS 漏洞的简单示例:

1
2
https://insecure-website.com/status?message=All+is+well.
<p>Status: All is well.</p>

应用程序不会对数据进行任何其他处理,因此攻击者可以构建类似的攻击:

1
2
https://insecure-website.com/status?message=<script>/*+Bad+stuff+here...+*/</script>
<p>Status: <script>/* Bad stuff here... */</script></p>

如果用户访问了攻击者构建的 URL,那么攻击者的脚本就会在该用户与应用程序的会话上下文中,在用户的浏览器中执行。此时,脚本可以执行任何操作,并检索用户可以访问的任何数据。

当应用程序接收 HTTP 请求中的数据,并以不安全的方式将该数据包含在即时响应中时,就会产生反射式跨站脚本攻击(或 XSS)。

假设一个网站有一个搜索功能,它在 URL 参数中接收用户提供的搜索词:

1
https://insecure-website.com/search?term=gift

应用程序会在对该 URL 的响应中呼应所提供的搜索词:

1
<p>You searched for: gift</p>

假定应用程序不对数据进行任何其他处理,攻击者就可以构建这样的攻击:

1
https://insecure-website.com/search?term=<script>/*+Bad+stuff+here...+*/</script>

该 URL 会得到以下响应:

1
<p>You searched for: <script>/* Bad stuff here... */</script></p>

如果应用程序的其他用户请求攻击者的 URL,那么攻击者提供的脚本就会在受害者用户的浏览器中,在其与应用程序的会话上下文中执行。

Lab: 将 XSS 反映到未编码的 HTML 上下文中

直接在搜索框搜索 <script>alert(1)</script> 就通关了

反射式 XSS 攻击的影响

如果攻击者可以控制受害者浏览器中执行的脚本,那么他们通常就可以完全控制该用户。其中,攻击者可以:

  • 在应用程序内执行用户可以执行的任何操作。

  • 查看用户可以查看的任何信息。

  • 修改用户可以修改的任何信息。

  • 启动与其他应用程序用户的交互,包括恶意攻击,这些攻击看似来自最初的受害用户。

攻击者可以通过各种手段诱使受害用户发出受其控制的请求,从而实施反射 XSS 攻击。这些手段包括在攻击者控制的网站上或允许生成内容的其他网站上放置链接,或在电子邮件、推特或其他信息中发送链接。攻击可以直接针对已知用户,也可以是针对应用程序任何用户的无差别攻击。

攻击需要外部传递机制,这意味着反射 XSS 的影响通常不如存储 XSS 严重,因为存储 XSS 可以在易受攻击的应用程序内部传递自带的攻击。

利用跨站点脚本漏洞

证明发现跨站脚本漏洞的传统方法是使用 alert() 函数创建一个弹出窗口。这并不是因为 XSS 与弹出窗口有什么关系;这只是一种证明您可以在给定域上执行任意 JavaScript 的方法。您可能会注意到有些人使用 alert(document.domain)。这是一种明确说明 JavaScript 在哪个域上执行的方法。

有时,你会想更进一步,通过提供一个完整的漏洞利用来证明 XSS 漏洞是一个真正的威胁。在本节中,我们将探讨三种最常用、最强大的 XSS 漏洞利用方法。

窃取 cookie 是一种利用 XSS 的传统方法。大多数网络应用程序都使用 cookie 进行会话处理。您可以利用跨站脚本漏洞,将受害者的 cookie 发送到自己的域,然后手动将 cookie 注入浏览器并假冒受害者。

实际上,这种方法有很大的局限性:

  • 受害者可能没有登录。

  • 许多应用程序会使用 HttpOnly 标志对 JavaScript 隐藏 cookie。

  • 会话可能被其他因素锁定,如用户的 IP 地址。

  • 会话可能会在你劫持之前超时。

本实验室包含博客评论功能中的存储 XSS 漏洞。模拟受害者用户会查看发布后的所有评论。要解决该实验问题,利用该漏洞渗出受害者的会话 cookie,然后使用该 cookie 冒充受害者。

不同情况下的反射 XSS

存储型XSS

当应用程序从不受信任的来源接收数据,并以不安全的方式将这些数据包含在随后的 HTTP 响应中时,就会产生存储 XSS(也称为持久或二阶 XSS)。

有关数据可能是通过 HTTP 请求提交给应用程序的;例如,博客文章上的评论、聊天室中的用户昵称或客户订单上的详细联系信息。在其他情况下,数据可能来自其他不受信任的来源;例如,显示通过 SMTP 收到的邮件的网络邮件应用程序、显示社交媒体帖子的营销应用程序或显示网络流量数据包的网络监控应用程序。

下面是一个存储 XSS 漏洞的简单示例。一个留言板应用程序允许用户提交信息,并显示给其他用户:

1
<p>Hello, this is my message!</p>

应用程序不会对数据进行任何其他处理,因此攻击者可以轻松发送攻击其他用户的信息:

1
<p><script>/* Bad stuff here... */</script></p>

基于 DOM 的跨站点脚本

基于 DOM 的 XSS(也称 DOM XSS)是指应用程序包含一些客户端 JavaScript,这些 JavaScript 以不安全的方式处理来自不信任源的数据,通常是将数据写回 DOM。

在下面的示例中,应用程序使用 JavaScript 从输入字段读取值,并将该值写入 HTML 中的一个元素:

1
2
3
var search = document.getElementById('search').value;
var results = document.getElementById('results');
results.innerHTML = 'You searched for: ' + search;

如果攻击者可以控制输入字段的值,他们就可以轻松构建一个恶意值,从而执行自己的脚本:

1
You searched for: <img src=1 onerror='/* Bad stuff here... */'>

在典型的情况下,输入字段将由 HTTP 请求的一部分填充,如 URL 查询字符串参数,从而允许攻击者使用恶意 URL 进行攻击,其方式与反射 XSS 相同。

XSS 可以用来做什么?

利用跨站脚本漏洞的攻击者通常能够:

  • 冒充或伪装成受害用户。

  • 执行用户能够执行的任何操作。

  • 读取用户能够访问的任何数据。

  • 获取用户的登录凭证。

  • 对网站进行虚拟篡改。

  • 在网站中注入木马功能。

XSS 漏洞的影响

XSS 攻击的实际影响通常取决于应用程序的性质、功能和数据,以及被攻击用户的状态。例如:

  • 在小册子软件应用程序中,所有用户都是匿名的,所有信息都是公开的,因此影响通常很小。

  • 在持有敏感数据(如银行交易、电子邮件或医疗记录)的应用程序中,影响通常会很严重。

  • 如果被入侵的用户在应用程序中拥有更高的权限,那么影响通常会非常严重,攻击者可以完全控制存在漏洞的应用程序,并入侵所有用户及其数据。

如何查找和测试 XSS 漏洞

绝大多数 XSS 漏洞都可以通过 Burp Suite 的网络漏洞扫描仪快速、可靠地发现。

手动测试反射和存储的 XSS 通常涉及向应用程序中的每个入口点提交一些简单的唯一输入(如一个简短的字母数字字符串),识别在 HTTP 响应中返回所提交输入的每个位置,并对每个位置进行单独测试,以确定适当制作的输入是否可用于执行任意 JavaScript。通过这种方法,您可以确定发生 XSS 的上下文,并选择合适的有效载荷加以利用。

手动测试由 URL 参数引起的基于 DOM 的 XSS 涉及类似的过程:在参数中放置一些简单的唯一输入,使用浏览器的开发工具在 DOM 中搜索该输入,并测试每个位置以确定其是否可被利用。然而,其他类型的 DOM XSS 更难检测。要在非基于 URL 的输入(如 document.cookie)或非基于 HTML 的汇(如 setTimeout)中发现基于 DOM 的漏洞,审查 JavaScript 代码是不可替代的,而审查 JavaScript 代码可能非常耗时。Burp Suite 的网络漏洞扫描器结合了 JavaScript 的静态和动态分析,能够可靠地自动检测基于 DOM 的漏洞。

内容安全政策

内容安全策略(CSP)是一种浏览器机制,旨在减轻跨站脚本和其他一些漏洞的影响。如果采用 CSP 的应用程序包含类似 XSS 的行为,那么 CSP 可能会阻碍或阻止对漏洞的利用。通常情况下,CSP 可被规避,以便利用底层漏洞。

悬挂标记注入

悬垂标记注入是一种技术,可用于在由于输入过滤器或其他防御措施而无法进行全面跨站脚本攻击的情况下跨域捕获数据。这种技术通常可用于捕获其他用户可见的敏感信息,包括可用于代表用户执行未授权操作的 CSRF 标记。

如何防止 XSS 攻击

在某些情况下,防止跨站脚本是一件小事,但根据应用程序的复杂程度和处理用户可控数据的方式,防止跨站脚本可能要难得多。

一般来说,有效防止 XSS 漏洞可能需要结合以下措施:

  • 在输入到达时进行过滤。在接收用户输入时,尽可能严格地根据预期或有效输入进行过滤。

  • 对输出数据进行编码。在 HTTP 响应中输出用户可控数据时,要对输出进行编码,防止其被解释为活动内容。根据输出上下文,这可能需要应用 HTML、URL、JavaScript 和 CSS 编码的组合。

  • 使用适当的响应标头。为防止在不打算包含任何 HTML 或 JavaScript 的 HTTP 响应中出现 XSS,可以使用 Content-TypeX-Content-Type-Options 标头,确保浏览器按您的意图解释响应。

  • 内容安全策略。作为最后一道防线,你可以使用内容安全策略(CSP)来降低仍然存在的任何 XSS 漏洞的严重性。

对输出数据进行编码。在 HTTP 响应中输出用户可控数据时,要对输出进行编码,防止其被解释为活动内容。根据输出上下文,这可能需要应用 HTML、URL、JavaScript 和 CSS 编码的组合。

有关跨站脚本的常见问题

XSS 漏洞有多常见?XSS 漏洞非常常见,XSS 可能是最常出现的网络安全漏洞。

XSS 攻击有多常见?很难获得有关真实世界中 XSS 攻击的可靠数据,但它被利用的频率可能低于其他漏洞。

XSS 和 CSRF 有什么区别?XSS 涉及导致网站返回恶意 JavaScript,而 CSRF 涉及诱使受害用户执行他们无意执行的操作。

XSS 与 SQL 注入有何区别?XSS 是针对其他应用程序用户的客户端漏洞,而 SQL 注入是针对应用程序数据库的服务器端漏洞。

如何在 PHP 中防止 XSS?使用允许字符的白名单过滤输入,并使用类型提示或类型转换。在 HTML 上下文中使用 htmlentitiesENT_QUOTES 对输出进行转义,在 JavaScript 上下文中使用 JavaScript Unicode 转义。

如何在 Java 中防止 XSS?使用允许字符白名单过滤输入,使用 Google Guava 等库对 HTML 上下文的输出进行 HTML 编码,或使用 JavaScript Unicode 转义对 JavaScript 上下文进行转义。

本文参考:

-------------本文结束感谢阅读-------------
创作不易,您的支持将鼓励我继续创作!