0x00前言
越高的楼层需要越牢固的地基,作为web安全最最需要的地基,同源策略的学习还是不能落下呀
0x01同源策略简介
源(origin)就是协议、域名和端口号,如果两个页面有相同的协议(HTTP,HTTPS),端口号,相同的host,那么可以判定这两个页面同源。
# | URL | 是否同源 | 原因 |
1 | https://christa.top/blogs | base | |
2 | https://christa.top/lists | 是 | |
3 | http://christa.top/lists | 否 | 协议不同 |
4 | https://christa.top:8080/lists | 否 | 端口不通 |
5 | https://test.christa.top/lists | 否 | host不同 |
同源策略是浏览器的一个安全功能,不同源客户端脚本在没有明确授权的情况下,不能读写对方资源,同源策略的限制范围:
- Cookie,localStorage,IndexDB无法读取
- DOM无法获得
- AJAX请求不能发送
跨域
在不是同源的情况下想要加载其脚本或者操作其他源的对象的时候就需要跨域,其方式有几种
1.通过降域document.domain
同源中认为域和子域属于不同的域,像test.domain.com
域domain.com
是属于不同的域,可以通过设置document.domain='domain.com'
,浏览器就会认为他们是同一个源,同时两个页面必须都设置document.domain='domain.com'
0x02JSONP
JSONP是浏览器与客户端跨域通信常用的一种方式。
JSONP使用过script标签加载数据的方式取获取数据当作JS代码来执行,提前在页面上声明一个函数,函数名通过接口传参的方式给后台,后台解析到函数名后在原始数据上并发送给前端。也就是说,JSONP需要对应接口的后端的配合才能实现。同时需要注意JSONP只支持GET方式的请求,不支持POST请求,JSONP的原理从script开始,script可以引用其他域的脚本文件,比如
<script src="http://domain.com/getInf"></script>
这时会向接口发送获取数据,这时候使用回调函数callback
出现了,其定义为对普通函数的调用:调用程序发出对普通函数的调用后,程序执行立即转向被调用函数执行,直到被调用函数执行完毕后,再返回调用程序继续执行。从发出调用的程序的角度看,这个过程为“调用-->等待被调用函数执行完毕-->继续执行”,src的callback参数是用来设置后端需要调用的回调函数的名字的,因此使用回调函数的shoData
来得到改数据
<script src="http://domain.com/getInf?callback=showData"></script>
这个请求到达后端后,后端会解析callback这个参数获取到的字符串showData,再对数据进行处理
<script>
function showData(inf){
console.log(inf)
}
</script>
<script src="http://domain2.com:8080/getNews?callback=showData"></script>
JSONP是通过script标签加载数据的方式取获取数据当做JS代码来执行,提前在页面上声明一个函数,函数名通过接口传参的方式传给后台,后台解析到函数名后在原始数据上包裹这个函数名,发送给前端。
0x03CORS
CORS是Access-Control-Allow-Origin (跨域资源共享)的缩写,是一种ajax跨域请求资源的方式,支持现代浏览器,IE支持到10以上。当使用XMLHttpRequest发送请求时,浏览器发现该请求不符合同源策略,则会给该请求加一个请求头:Orgin,后台进行一系列处理,如果确定接受请求则在返回结果中加一个响应头:Access-Control-Allow-Orgin;流浪其判断该响应头中是否包含Orgin的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含则直接驳回。它允许一下几种发起跨域请求
- 由XMLHttpRequest或Fetch等发起的跨域请求;
- Web 字体,通过 @font-face 进行跨域调用;
- WebGL 贴图;
- 使用 drawImage 将 Images/video 画面绘制到 canvas;
- 样式表(使用 CSSOM)
- script;
大致的CORS的header类型如下
- Access-Control-Allow-Origin 指定哪些域可以访问本域的资源。例如,如果
requester.com
想要访问provider.com
的资源,那么开发人员可以用此授予requester.com
访问provider.com
资源的权限- Access-Control-Allow-Credentials 指定浏览器是否将使用请求发送cookie。仅当
allow-credentials
标头设置为true
时,才会发送cookie。- Access-Control-Allow-Methods 指定可以使用哪些HTTP请求方法(GET,PUT,DELETE等)来访问资源。开发人员可用其进一步加强控制力,增强安全性。
- Access-Control-Allow-Headers 提供一个逗号分隔的列表表示服务器支持的请求数据类型。假如你使用自定义头部(比如:x-authentication-token 服务器需要在返回OPTIONS请求时,要把这个值放到这个头部里,否则请求会被阻止)。
- Orgin 这个头部信息,属于请求数据的一部分。这个值表明这个请求是从浏览器打开的哪个域名下发出的。出于安全原因,浏览器不允许你修改这个值。
- Access-Control-Expose-Headers 相似的,这个返回信息里包含了一组头部信息,这些信息表示那些客户端可以使用。其他没有在里面的头部信息将会被限制
首先,让我们通过js发送一个POST请求
function sendData() {
var request = new XMLHttpRequest(),
payload = 'test';
request.open('POST', 'http://127.0.0.1/CORS_req.php', true);
request.setRequestHeader('X-CUSTOM-HEADER', 'custom_header_value');
request.send(payload);
}
不同的域中会产生Orgin的部分,同时拒绝返回服务,而相同的源则不会
拒绝返回
其常见的CORS的攻击场景为
CORS中header滥用通配符(*)
信任域的配置存在缺陷
当开发人员配置了CORS,但是白名单只有requester.com,但是但攻击者发起以下的请求
GET /api/userinfo.php
Host: example.com
Connection: close
Origin: attackerrequester.com
则很可能服务器对此产生响应,发生这种情况的原因是可能的后端配置错误
使用XSS实现CORS攻击
开发人员用于对抗CORS攻击的一种防御机制是将一些频繁请求的域列入白名单。但是,这也有缺陷,若白名单中某个域的子域容易受到其他攻击(如XSS)的影响,它也会影响CORS的安全性。