跨站资源共享(CORS)漏洞的误配置及检测⽅法
基本知识
同源策略(Same Origin Policy, SOP)
同源策略是浏览器级别的安全机制。它的核⼼观点是,来⾃不同源(域名、端⼝或者协议有⼀项不同都算)的Web应⽤不共享任何资源。
例如,在⽗页⾯中建⽴⼀个iframe标签指向另⼀个域名,⽗页⾯和iframe属于不同源,不能相互读取DOM树。⽗页⾯只能控制iframe发送get或post请求,却不能读取请求的内容。但有时候,我们需要在不同域的web应⽤之间交换数据,这时候有以下⼏种常⽤的跨域⽅法:JSONP,window.postMessage(),CORS。
跨域资源共享(Cross-Origin Resource Sharing, CORS)
CORS的原理是,当我们要进⾏跨域请求时,在服务端的响应头中加⼊相应header,通知浏览器添加特例放宽同源策略的限制。重要的响应头有:
- Access-Control-Allow-Origin: a.com 服务端接受来⾃a.com的跨域请求
个人业绩报告
- Access-Control-Allow-Credentials: true表⽰是否允许发送Cookie,true即发送cookie
如果a.com要和b.com通信,且b.com可以⽤如下代码开启CORS响应头:
<?php
header("Access-Control-Allow-Origin: a.com");
header("Access-Control-Allow-Credentials: true");
>
⽽a.com可以使⽤下⾯的js代码与b.com通信,读取b.com的内容:
var xhr=new XMLHttpRequest();
if (adyState == XMLHttpRequest.DONE) {
sponText);
}
}
xhr.open(“GET“, ”b.com/api“, true);
xhr.withCredentials = true;
xhr.nd();
CORS误配置及检测⽅法
检测CORS配置错误相对⽐较简单,因为⼤部分服务器都是使⽤请求包的Origin头进⾏控制的,⽽我们可以任意修改Origin头。只要对⽐响应头中ACAO和ACAC的变化,便可以判断是否存在漏洞。基本脚本如下:
import requests
acao = ''
acac = ''
headers = {'Origin': 'test'}
r = ('192.168.140.129/cors/1.php', headers=headers)
if'Access-Control-Allow-Origin'in r.headers:
acao = r.headers['Access-Control-Allow-Origin']
if'Access-Control-Allow-Credentials'in r.headers:
acac = r.headers['Access-Control-Allow-Credentials']
print("Access-Control-Allow-Origin: " + acao)
print("Access-Control-Allow-Credentials: " + acac)
反射Origin头
为了安全考虑,ACAO头默认不允许填写多个域名。有些开发者为了⽅便,直接在Access-Control-Allow-Origin中反射请求的Origin值。作为ACAO的域名,这样使得所有⼈都可以轻易访问该域名内容,窃取隐私数据。
服务端代码为:
<?php
header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
header("Access-Control-Allow-Credentials: true");
>
错误 Nginx 配置⽰例:
add_header "Access-Control-Allow-Origin" $http_origin;
add_header “Access-Control-Allow-Credentials” “true”;
这种配置⾮常危险,相当于信任任意⽹站,给攻击者⽹站敞开了⼤门。任意攻击者⽹站可以直接跨域读取其资源内容。
检测⽅法:
使⽤不同Origin头请求同⼀个服务器,查看响应头中Access-Control-Allow-Origin是否总是与Origin相同。
Origin校验错误
有些Origin检测的⽅法⽐较宽松,造成只匹配了前缀、后缀、没有转义”.”等情况。
检测⽅法:
busy副词先发送⼀个请求,得到CORS头后,在其中加⼊前缀、后缀以及将”.”替换成任意字符,查看响应头是否同步变化
信任null
有些web应⽤为了与本地file页⾯共享数据,将ACAO头设置为Null,但攻击者可以使⽤如下代码发送Origin为Null的请求。
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src='data:text/html,<script>var xhr=new XMLHttpRequest();
if (adyState == XMLHttpRequest.DONE) {
sponText);
}
}
xhr.open("GET", "45.32.105.30:8080", true);
xhr.withCredentials = true;
xhr.nd();</script>'></iframe>
检测⽅法:
直接检测返回头CORS是否是NULL即可医疗保健行业
HTTPS域信任HTTP域
如果https域的应⽤信任⾮http域,那么攻击者可以先劫持受信任的http域,然后通过这个域发送跨域请求到https站,从⽽盗取信息。
检测⽅法:
直接检测https站点返回头CORS是否信任http即可
信任⾃⾝任意⼦域
有些应⽤过分信⽤⾃⾝⼦域,当⼦域中发⽣XSS时,会放⼤XSS的危害。
检测⽅法:
在请求Origin中发送⽬标站点的⼦域名,检查返回头ACAO
Origin: *与 Credentials: true 共⽤
许三观卖血记读后感>大禹是谁的儿子如果是开放的公共资源,origin才会设置成通配符”*”,这种资源不应该允许携带cookie等访问。
浏览器会对下⾯这种误配置报错:
Access-Control-Allow-Origin:*
Access-Control-Allow-Credentials:true
这就意味着,Access-Control-Allow-Origin:*只能⽤于共享公开资源。
检测⽅法:
直接检查⽬标返回头即可。
缺少Vary: Origin头小刀豆
如果⼀个资源享有多个域名,它需要对不同域名的请求包⽣成不同的ACAO头。如果⼀个请求的响应被缓存,且返回中没有Vary: Origin字段,可能会导致其它域名的请求失效。
检测⽅法:
⽆法检测,因为我们不知道⼀个服务器是否共享多个域名。
CORS漏洞扫描⼯具
CORS安全配置最佳实践
1. 不要盲⽬反射 Origin头
2. 严格校验 Origin 头,避免出现权限泄露
3. 不要配置 Access-Control-Allow-Origin: null
4. HTTPS ⽹站不要信任HTTP 域
5. 不要信任全部⾃⾝⼦域,减少攻击⾯
6. 不要配置 Origin:*和 Credentials: true前鼻音后鼻音
7. 增加 Vary: Origin 头
参考链接: