返回介绍

Mechanisms

发布于 2024-10-11 20:34:03 字数 23179 浏览 0 评论 0 收藏 0

Here’s a quick review of how the SOP works. Because of the SOP, a script from page A can access data from page B only if the pages are of the same origin. Two URLs are said to have the same origin if they share the same protocol, hostname, and port number. Modern web applications often base their authentication on HTTP cookies, and servers take action based on the cookies included automatically by the browser. This makes the SOP especially important. When the SOP is implemented, malicious web pages won’t be able to take advantage of the cookies stored in your browser to access your private information. You can read more about the details of the SOP in Chapter 3 .

这里简要介绍 SOP 的工作原理。由于 SOP 的存在,仅当页面 A 和 B 属于相同的来源时,页面 A 的脚本才能访问页面 B 的数据。如果两个 URL 具有相同的协议,主机名和端口号,则它们被视为具有相同的来源。现代 Web 应用程序通常基于 HTTP Cookie 进行身份验证,并且服务器根据浏览器自动包含的 Cookie 采取行动。这使得 SOP 尤为重要。当 SOP 实施时,恶意网页将无法利用存储在您的浏览器中的 Cookie 来访问您的私人信息。您可以在第 3 章中了解有关 SOP 的详细信息。

Practically, the SOP is often too restrictive for modern web applications. For example, multiple subdomains or multiple domains of the same organization wouldn’t be able to share information if they followed the policy. Since the SOP is inflexible, most websites find ways to relax it. This is often where things go wrong.

实际上,同源策略对于现代网络应用程序来说经常过于严格。例如,如果按照该策略,同一组织的多个子域或多个域名将无法共享信息。由于同源策略不灵活,大多数网站都会找到放宽策略的方法,而这往往会导致问题。

For instance, imagine that you are an attacker trying to smuggle information out of a banking site, a.example.com , and find a user’s account number. You know that a user’s banking details are located at a.example.com/user_info . Your victim is logged into the banking site at a.example.com and is also visiting your site, attacker.com , in the same browser.

例如,想象一下你是一个攻击者,试图从银行网站 a.example.com 走私信息,并找到一个用户的帐号。您知道用户的银行详细信息位于 a.example.com/user_info。您的受害者已登录到 a.example.com 的银行网站,并在同一浏览器中访问您的网站 attacker.com。

Your site issues a GET request to a.example.com/user_info to retrieve the victim’s personal information. Since your victim is logged into the bank, their browser automatically includes their cookies in every request it sends to a.example.com , even if the request is generated by a script on your malicious site. Unfortunately, because of the SOP, the victim’s browser won’t allow your site to read data returned from a.example.com .

您的网站向 a.example.com/user_info 发送 GET 请求以检索受害者的个人信息。由于受害者已登录银行,他们的浏览器会自动将 cookies 包含在发送到 a.example.com 的每个请求中,即使请求是由您的恶意网站上的脚本生成的。不幸的是,由于 SOP 的原因,受害者的浏览器不允许您的网站读取从 a.example.com 返回的数据。

But now, say you realize that a.example.com passes information to b.example.com via SOP bypass techniques. If you can find out the technique used and exploit it, you might be able to steal the victim’s private information on the banking site.

但是现在,假设你意识到 a.example.com 通过 SOP 绕过技术向 b.example.com 传递信息。如果你能找出所使用的技术并利用它,你就有机会在银行网站上窃取受害者的私人信息。

The simplest way for websites to work around the SOP is to change the origin of a page via JavaScript. Setting the origin of two pages to the same domain using document.domain in the pages’ JavaScript will enable the pages to share resources. For example, you can set the domain of both a.example.com and b.example.com to example.com so that they can interact:

网站绕过 SOP 的最简单方法是通过 JavaScript 更改页面的来源。在页面的 JavaScript 中使用 document.domain 将两个页面的来源设置为相同的域,将使页面共享资源。例如,您可以将 a.example.com 和 b.example.com 的域设置为 example.com,以便它们可以交互。

document.domain = "example.com"

However, this approach has its limitations. First, you can only set the document.domain of a page to a superdomain; for example, you can set the origin of a.example.com to example.com , but not to example2.com . Therefore, this method will work only if you want to share resources with superdomains or sibling subdomains.

然而,这种方法也有它的局限性。首先,你只能将页面的 document.domain 设为一个上级域名;例如,你可以将 a.example.com 的来源设为 example.com,但不能设为 example2.com。因此,这种方法只能在你想与上级域或同级子域名共享资源时才能使用。

Exploiting Cross-Origin Resource Sharing

Because of these limitations, most sites use Cross-Origin Resource Sharing (CORS) to relax the SOP instead. CORS is a mechanism that protects the data of the server. It allows servers to explicitly specify a list of origins that are allowed to access its resources via the HTTP response header Access-Control-Allow-Origin .

由于这些限制,大多数网站使用跨域资源共享(CORS)来放宽 SOP。CORS 是一种保护服务器数据的机制。它允许服务器通过 HTTP 响应头 Access-Control-Allow-Origin 显式地指定一组允许访问其资源的原点列表。

For example, let’s say we’re trying to send the following JSON blob located at a.example.com/user_info to b.example.com :

例如,假设我们正在尝试将位于 a.example.com/user_info 的以下 JSON 数据块发送到 b.example.com:

{"username": "vickieli", "account_number": "12345"}

Under the SOP, b.example.com won’t be able to access the JSON file, because a.example.com and b.example.com are of different origins. But using CORS, the user’s browser will send an Origin header on behalf of b.example.com :

根据 SOP,b.example.com 将无法访问 JSON 文件,因为 a.example.com 和 b.example.com 属于不同的来源。但是使用 CORS,用户的浏览器将代表 b.example.com 发送 Origin 标头:

Origin: https://b.example.com

If b.example.com is part of an allowlist of URLs with permission to access resources on a.example.com , a.example.com will send the browser the requested resource along with an Access-Control-Allow-Origin header. This header will indicate to the browser that a specific origin is allowed to access the resource:

如果 b.example.com 是 URL 允许列表中的一部分,具有访问 a.example.com 资源的权限,a.example.com 将向浏览器发送请求的资源以及 Access-Control-Allow-Origin 头。该头将指示浏览器允许特定来源访问资源。

Access-Control-Allow-Origin: b.example.com

The application can also return the Access-Control-Allow-Origin header with a wildcard character ( * ) to indicate that the resource on that page can be accessed by any domain:

该应用程序还可以返回 Access-Control-Allow-Origin 头带有通配符字符(*),以表示该页面上的资源可被任何域名访问。

Access-Control-Allow-Origin: *

On the other hand, if the origin of the requesting page isn’t allowed to access the resource, the user’s browser will block the requesting page from reading the data.

另一方面,如果请求页面的来源未被允许访问该资源,用户的浏览器将阻止请求页面读取数据。

CORS is a great way to implement cross-origin communication. However, CORS is safe only when the list of allowed origins is properly defined. If CORS is misconfigured, attackers can exploit the misconfiguration and access the protected resources.

CORS 是一种很好的实现跨域通信的方式。然而,只有在正确定义允许访问的来源列表时,CORS 才是安全的。如果 CORS 配置不正确,攻击者可以利用这种错误配置来访问被保护的资源。

The most basic misconfiguration of CORS involves allowing the null origin. If the server sets Access-Control-Allow-Origin to null , the browser will allow any site with a null origin header to access the resource. This isn’t safe because any origin can create a request with a null origin. For instance, cross-site requests generated from a document using the data: URL scheme will have a null origin.

CORS 的最基本的配置错误是允许 null origin。如果服务器将 Access-Control-Allow-Origin 设置为 null,浏览器将允许任何带有 null origin 头的站点访问资源。这不安全,因为任何来源都可以创建具有 null origin 的请求。例如,使用 data: URL 方案创建的文档生成的跨站请求将具有 null origin。

Another misconfiguration is to set the Access-Control-Allow-Origin header to the origin of the requesting page without validating the requestor’s origin. If the server doesn’t validate the origin and returns an Access-Control-Allow-Origin for any origin, the header will completely bypass the SOP, removing all limitations on cross-origin communication.

另一个配置问题是在未验证请求者的来源情况下将 Access-Control-Allow-Origin 头设置为请求页面的来源。如果服务器不验证来源并为任何来源返回 Access-Control-Allow-Origin,则此头将完全绕过 SOP,在跨域通信方面删除所有限制。

In summary, if the server sets the Access-Control-Allow-Origin header to null or to arbitrary origins of the requesting page, it allows attackers to smuggle information offsite:

总之,如果服务器将 Access-Control-Allow-Origin 头设置为 null 或请求页面的任意来源,它允许攻击者将信息从站点外走私。

Access-Control-Allow-Origin: null
Access-Control-Allow-Origin: https://attacker.com

Another exploitable misconfiguration occurs when a site uses weak regexes to validate origins. For example, if the policy checks only if an origin URL starts with www.example.com , the policy can be bypassed using an origin like www.example.com.attacker.com .

另一个可利用的配置错误是当网站使用弱的正则表达式来验证来源时发生。例如,如果策略仅检查起始源 URL 是否以 www.example.com 开头,则可以使用类似 www.example.com.attacker.com 的来源绕过该策略。

Access-Control-Allow-Origin: https://www.example.com.attacker.com

An interesting configuration that isn’t exploitable is setting the allowed origins to the wildcard ( * ). This isn’t exploitable because CORS doesn’t allow credentials, including cookies, authentication headers, or client-side certificates, to be sent with requests to these pages. Since credentials cannot be sent in requests to these pages, no private information can be accessed:

一个有趣的设置是将允许来源设置为通配符(*)。这不可利用,因为 CORS 不允许凭据(包括 Cookie,身份验证标头或客户端证书)与请求一起发送到这些页面。由于不能在请求中发送凭证到这些页面,因此不能访问私人信息。

Access-Control-Allow-Origin: *

Developers can prevent CORS misconfigurations by creating a well-defined CORS policy with a strict allowlist and robust URL validation. For pages containing sensitive information, the server should return the requesting page’s origin in the Access-Control-Allow-Origin header only if that origin is in the allowlist. For public information, the server can simply use the wildcard * designation for Access-Control-Allow-Origin .

开发者可以通过创建一个明确定义的 CORS 策略并进行严格的白名单和 URL 验证来防止 CORS 配置不当。对于包含敏感信息的页面,只有该域名在白名单中时,服务器才会在 Access-Control-Allow-Origin 头中返回请求页面的源。对于公开信息,服务器可以使用通配符 * 来指定 Access-Control-Allow-Origin。

Exploiting postMessage()

Some sites work around SOP by using postMessage() . This method is a web API that uses JavaScript syntax. You can use it to send text-based messages to another window:

一些网站用 postMessage() 规避 SOP,这种方法是一种使用 JavaScript 语法的 Web API。您可以使用它向另一个窗口发送基于文本的消息:

RECIPIENT_WINDOW.postMessage(MESSAGE_TO_SEND, TARGET_ORIGIN);

The receiving window would then handle the message by using an event handler that will be triggered when the receiving window receives a message:

接收窗口将通过使用事件处理程序来处理消息,该事件处理程序将在接收窗口接收到消息时触发。

window.addEventListener("message",EVENT_HANDLER_FUNCTION);

Since using postMessage() requires the sender to obtain a reference to the receiver’s window, messages can be sent only between a window and its iframes or pop-ups. That’s because only windows that open each other will have a way to reference each other. For example, a window can use window.open to refer to a new window it opened. Alternatively, it can use window.opener to reference the window that spawned the current window. It can use window.frames to reference embedded iframes, and window.parent to reference the parent window of the current iframe.

由于使用 postMessage()需要发送者获取对接收者窗口的引用,因此消息只能在窗口和它的 iframe 或弹出窗口之间发送。这是因为只有相互打开的窗口才有互相引用的方法。例如,窗口可以使用 window.open 引用它打开的新窗口。或者,它可以使用 window.opener 引用生成当前窗口的窗口。它可以使用 window.frames 引用嵌入的 iframes,并使用 window.parent 引用当前 iframe 的父窗口。

For example, say we’re trying to pass the following JSON blob located at a.example.com/user_info to b.example.com :

例如,假设我们正在尝试将位于 a.example.com/user_info 的以下 JSON 块传递到 b.example.com:

{'username': 'vickieli', 'account_number': '12345'}

a.example.com can open b.example.com and send a message to its window. The window.open() function opens the window of a particular URL and returns a reference to it:

a.example.com 可以打开 b.example.com 并向其窗口发送信息。 window.open()函数打开特定 URL 的窗口并返回对其的引用:

var recipient_window = window.open("https://b.example.com", b_domain)
recipient_window.postMessage("{'username': 'vickieli', 'account_number': '12345'}", "*");

At the same time, b.example.com would set up an event listener to process the data it receives:

同时,b.example.com 将设置一个事件监听器来处理它接收到的数据。

function parse_data(event) {
  // Parse the data
}
window.addEventListener("message", parse_data);

As you can see, postMessage() does not bypass SOP directly but provides a way for pages of different origins to send data to each other.

你可以看到,postMessage()并不直接绕过同源策略,但为不同源的页面提供了一种相互发送数据的方式。

The postMessage() method can be a reliable way to implement cross-origin communication. However, when using it, both the sender and the receiver of the message should verify the origin of the other side. Vulnerabilities happen when pages enforce weak origin checks or lack origin checks altogether.

“postMessage()方法可以是实现跨源通信的可靠方式。但是,使用它时发送者和接收者都应验证对方的来源。弱的来源检查或完全缺少来源检查的页面会产生漏洞。”

First, the postMessage() method allows the sender to specify the receiver’s origin as a parameter. If the sender page doesn’t specify a target origin and uses a wildcard target origin instead, it becomes possible to leak information to other sites:

首先,postMessage() 方法允许发送者将接收者的来源作为参数指定。如果发送者页面没有指定目标来源,而是使用通配符目标来源,那么就可能向其他网站泄露信息。

RECIPIENT_WINDOW.postMessage(MESSAGE_TO_SEND, *);

In this case, an attacker can create a malicious HTML page that listens for events coming from the sender page. They can then trick users into triggering the postMessage() by using a malicious link or fake image and make the victim page send data to the attacker’s page.

在这种情况下,攻击者可以创建一个恶意的 HTML 页面,监听来自发送者页面的事件。然后,他们可以通过使用恶意链接或假图像欺骗用户触发 postMessage(),并让受害页面将数据发送到攻击者的页面。

To prevent this issue, developers should always set the TARGET_ORIGIN parameter to the target site’s URL instead of using a wildcard origin:

为了防止这个问题,开发者应该始终将 "TARGET_ORIGIN" 参数设置为目标站点的 URL,而不是使用通配符。

recipient_window.postMessage(
"{'username': 'vickieli', 'account_number': '12345'}",     "https://b.example.com" );

On the other hand, if the message receiver doesn’t validate the page where the postMessage() is coming from, it becomes possible for attackers to send arbitrary data to the website and trigger unwanted actions on the victim’s behalf. For example, let’s say that b.example.com allows a.example.com to trigger a password change based on a postMessage() , like this:

另外,如果信息接收方不验证 postMessage()来源的页面,则攻击者可以向网站发送任意数据,并以受害者的名义触发不必要的操作。例如,假设 b.example.com 允许 a.example.com 根据 postMessage()触发密码更改,如下所示:

recipient_window.postMessage(
"{'action': 'password_change', 'username': 'vickieli', 'new_password': 'password'}", 
"https://b.example.com");

The page b.example.com would then receive the message and process the request:

页面 b.example.com 将接收并处理请求:

function parse_data(event) {
  // If "action" is "password_change", change the user's password
}
window.addEventListener("message", parse_data);

Notice here that any window can send messages to b.example.com , so any page can initiate a password change on b.example.com ! To exploit this behavior, the attacker can embed or open the victim page to obtain its window reference. Then they’re free to send arbitrary messages to that window.

请注意,任何窗口都可以向 b.example.com 发送消息,因此任何页面都可以在 b.example.com 上发起密码更改!攻击者可以利用这种行为嵌入或打开受害者页面以获取其窗口引用。然后,他们可以自由地向该窗口发送任意消息,从而利用此漏洞。

To prevent this issue, pages should verify the origin of the sender of a message before processing it:

为了避免这个问题,页面在处理邮件前应该验证发件人的来源。

function parse_data(event) {
1 if (event.origin == "https://a.example.com"){

    // If "action" is "password_change", change the user's password
  }
}
window.addEventListener("message", parse_data);

This line 1 verifies the origin of the sender by checking it against an acceptable origin.

这一行通过将其与可接受的来源进行比较来验证发送者的来源。

Exploiting JSON with Padding

JSON with Padding ( JSONP) is another technique that works around the SOP. It allows the sender to send JSON data as JavaScript code. A page of a different origin can read the JSON data by processing the JavaScript.

JSONP 是另一种可以绕过同源策略的技术。它允许发送器将 JSON 数据作为 JavaScript 代码发送。不同源的页面可以通过处理 JavaScript 来读取 JSON 数据。

To see how this works, let’s continue with our previous example, where we’re trying to pass the following JSON blob located at a.example.com/user_info to b.example.com :

为了了解它的工作原理,让我们继续使用我们之前的示例,我们试图将位于 a.example.com/user_info 的以下 JSON 块传递给 b.example.com:

{"username": "vickieli", "account_number": "12345"}

The SOP allows the HTML <script> tag to load scripts across origins, so an easy way for b.example.com to retrieve data across origins is to load the data as a script in a <script> tag:

SOP 允许 HTML <script>标签跨域加载脚本,因此 b.example.com 跨域检索数据的简单方法是将数据作为<script>标签中的脚本加载:

<script src="https://a.example.com/user_info"></script>

This way, b.example.com would essentially be including the JSON data block in a script tag. But this would cause a syntax error because JSON data is not valid JavaScript:

这样,b.example.com 实际上会在一个脚本标签中包含 JSON 数据块。但这会导致语法错误,因为 JSON 数据不是合法的 JavaScript 语法。

<script>
    {"username": "vickieli", "account_number": "12345"}
</script>

JSONP works around this issue by wrapping the data in a JavaScript function, and sending the data as JavaScript code instead of a JSON file.

JSONP 通过将数据包装在一个 JavaScript 函数中,将数据作为 JavaScript 代码而不是 JSON 文件发送,从而解决了这个问题。

The requesting page includes the resource as a script and specifies a callback function, typically in a URL parameter named callback or jsonp . This callback function is a predefined function on the receiving page ready to process the data:

请求页面包含资源作为一个脚本,并指定一个回调函数,通常在名为 callback 或 jsonp 的 URL 参数中。这个回调函数是接收页面上预定义的函数,可以处理数据:

<script src="https://a.example.com/user_info?callback=parseinfo"></script>

The page at a.example.com will return the data wrapped in the specified callback function:

页面 a.example.com 将返回指定回调函数包装的数据:

parseinfo({"username": "vickieli", "account_number": "12345"})

The receiving page would essentially be including this script, which is valid JavaScript code:

接收页面基本上将包含此脚本,这是有效的 JavaScript 代码:

<script>
    parseinfo({"username": "vickieli", "account_number": "12345"})
</script>

The receiving page can then extract the data by running the JavaScript code and processing the parseinfo() function. By sending data as scripts instead of JSON data, JSONP allows resources to be read across origins. Here’s a summary of what happens during a JSONP workflow:

接收页面可以通过运行 JavaScript 代码并处理 parseinfo() 函数来提取数据。通过将数据作为脚本而不是 JSON 数据发送,JSONP 允许跨来源读取资源。以下是 JSONP 工作流程的摘要:

  1. The data requestor includes the data’s URL in a script tag, along with the name of a callback function.
  2. The data provider returns the JSON data wrapped within the specified callback function.
  3. The data requestor receives the function and processes the data by running the returned JavaScript code.

You can usually find out if a site uses JSONP by looking for script tags that include URLs with the terms jsonp or callback .

你可以通过查找包含 jsonp 或 callback 术语的 URL 的脚本标签来通常找到一个网站是否使用 JSONP。

But JSONP comes with risks. When JSONP is enabled on an endpoint, an attacker can simply embed the same script tag on their site and request the data wrapped in the JSONP payload, like this:

但 JSONP 存在风险。当启用 JSONP 时,攻击者可以在其网站上嵌入相同的脚本标签,并使用 JSONP 有效负载封装请求的数据,像这样:

<script src="https://a.example.com/user_info?callback=parseinfo"></script>

If a user is browsing the attacker’s site while logged into a.example.com at the same time, the user’s browser will include their credentials in this request and allow attackers to extract confidential data belonging to the victim.

如果用户同时在登录 a.example.com 的情况下浏览攻击者网站,则用户的浏览器将包含他们的凭据以及请求,这将使攻击者能够提取属于受害者的机密数据。

This is why JSONP is suitable for transmitting only public data. While JSONP can be hardened by using CSRF tokens or maintaining an allowlist of referer headers for JSONP requests, these protections can often be bypassed.

这就是为什么 JSONP 只适用于传递公共数据的原因。虽然可以通过使用 CSRF 令牌或维护 JSONP 请求的 refer 头名单来增强 JSONP 的安全性,但是这些保护措施经常会被绕过。

Another issue with JSONP is that site b.example.com would have to trust site a.example.com completely, because it’s running arbitrary JavaScript from a.example.com . If a.example.com is compromised, the attacker could run whatever JavaScript they wanted on b.example.com , because b.example.com is including the file from a.example.com in a <script> tag. This is equivalent to an XSS attack.

JSONP 还存在另一个问题,即网站 b.example.com 必须完全信任网站 a.example.com,因为它正在从 a.example.com 运行任意 JavaScript。如果 a.example.com 遭到攻击,攻击者可以在 b.example.com 上运行任何想要的 JavaScript,因为 b.example.com 在<script>标签中包含了来自 a.example.com 的文件。这相当于一次 XSS 攻击。

Now that CORS is a reliable option for cross-origin communication, sites no longer use JSONP as often.

由于 CORS 已成为跨域通讯的可靠选项,因此网站不再经常使用 JSONP。

Bypassing SOP by Using XSS

Finally, XSS is essentially a full SOP bypass, because any JavaScript that runs on a page operates under the security context of that page. If an attacker can get a malicious script executed on the victim page, the script can access the victim page’s resources and data. Therefore, remember that if you can find an XSS, you’ve essentially bypassed the SOP protecting that page.

最后,XSS 本质上是完全绕过 SOP,因为在页面上运行的任何 JavaScript 都在该页面的安全上下文下操作。如果攻击者能够在受害者页面上执行恶意脚本,该脚本就可以访问受害者页面的资源和数据。因此,请记住,如果您能找到 XSS 漏洞,您本质上是绕过了保护该页面的 SOP。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文