同源策略和CORS
一:同源策略
什么是同源策略?
同源策略(same-orgin policy)是一种约定,web是构建在同源策略之上的,浏览器是针对同源策略的一种实现。同源策略最初是指不同源的A网页的cookie不能被B网页的获得,后来扩展对dom操作,XmlHttpRequest也做了限制
何为同源?
- 协议相同
- 域名相同
- 端口相同
只有同时满足以上三个条件才谓之同源
同源策略的三个方面
- Cookie同源策略:不同源cookie不共享
- DOM同源策略:禁止对不同源的页面dom操作,主要针对的是iframe跨域
- XmlHttpRequest同源策略:禁止使用XmlHttpRequet向不同域发起请求,例如ajax请求
下面看一下ajax跨域请求,浏览器的显示
AJAX跨域测试
点击button,ajax发起跨域请求
看一下Chrome显示
火狐
为何要有同源策略
同源策略的目的就是保障用户的信息安全,防止恶意网站窃取数据,下面通过DOM和XmlHttpRequest来说明
如果没有Dom同源策略
- 现在有一个假网站,通过iframe嵌入了一个银行网站
- 通过设置将银行网站的宽高设置到合适比例,让这个假网站在浏览器上面除了url不同,其他都和银行网站一模一样
- 用户在iframe嵌套的银行网站中输入了密码和账户名称
- 在iframe的外层通过dom操作获得用户的密码和账户
- 这样用户的密码和账户信息就被窃取了
如果没有XmlHttpRequest同源策略
- 用户登录银行网站,提交登录表单,银行服务器通过验证,为了维持对话返回Cookie
- 这时用户又浏览了另一个网站,而这个网站就是一个恶意网站
- 恶意网站后台向银行网站发起ajax请求,请求携带第一步银行的cookie,银行服务器通过cookie验证了用户身份,响应这个假冒用户的请求
- 这样用户的信息又泄漏了,而且是后台发起ajax请求,所以用户不会感知到这个过程
所以在同源策略的保护下,我们可以安全的上网
CORS
跨域限制
因为同源策略,所以浏览器的跨域请求被限制,但是有些时候跨域操作又是必须的;例如在CAS实现SSO的过程中,就需要在访问子系统的时候将浏览器重定向到CAS Server。
解决方案之CORS
CORS(cross orign resource sharing)即跨域资源共享,是一个W3C标准,它允许浏览器向不同源的服务器发起XmlHttpRequest请求,从而克服了AJAX,重定向只能同源使用的限制
CORS的实现需要浏览器和服务器的同时支持,整个CORS的通信过程是在后台进行的,不需要用户的参与,浏览器会根据跨域请求,自动为请求的request header额外添加一些字段,对于部分跨域请求还会在真正发出跨域请求之前发送一个preflight请求。
目前所有的浏览器都支持CORS,IE浏览器版本不能低于IE10,所以实现CORS的关键在于服务器,我认为这也正常,因为你是跨域访问我,不是我的人,还想要的资源,肯定得征得我同意呀。
俩种请求
浏览器将CORS请求分为俩类:简单请求和非简单请求
简单请求需要同时满足以下俩个条件
- 请求方法是 HEAD,GET,POST之一
- HTTP的头字段不能超出以下几个
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type: 只限于三个值application/x-www.form-urlencded,multipart/form-data,text/plain
凡不是简单请求的都是非简单请求(废话!!!)
简单请求跨域流程
- 对于简单跨域请求,浏览器会直接向服务器发起请求,并且在请求头中添加Origin字段来说明源信息例如协议端口域名。
- 服务器可以通过这个字段来决定是否同意这次请求。Origin的源在服务器允许的范围内,那么服务器就会在response中添加一个Access-Control-Origin :true,如果服务器不允许,那么在浏览器端发现响应中没有Access-Control-Origin字段就会抛出一个错误。
- 默认浏览器不会跨域携带Cookie,如果需要,ajax请求需要设置属性withCredentials属性为true,服务器需要设置相应头部Access-Control-Allow-Credentials:true
非简单请求跨域流程
对于非简单跨域请求,浏览器会在真正发起请求前先发起一个Preflight请求给服务器,请求method使用OPTIONS,头部会加入下列信息
Origin : 源信息
Access-Control-Request-Method : 列出请求使用的方法
Access-Control-Request-Headers:自定义的头部信息
看一个例子,实践出真知
$(".btn").click(function(){
$.ajax({
url:"https://www.baidu.com",
type:"get",
headers:{
"CONTENT":"TEST"
}//添加了自定义headers,所以是非简单请求
})
})
浏览器F12查看network,果然浏览器提前发送了preflight请求,并且添加了相关字段
发送preflight后,服务器端可以根据Origin,Access-Control-Request-Method和Access-Control-Request-Headers决定是否允许请求,当在允许的响应中会添加如下字段
Access-Control-Allow-Origin:与简单的请求相同。*代表同意任何跨域请求
Access-Control-Allow-Methods: 允许的方法,多个方法以逗号分隔。
Access-Control-Allow-Headers: 允许的头部,多个方法以逗号分隔。
Access-Control-Max-Age: 应该将这个 Preflight 请求缓存多长时间(以秒表示)。
Access-Control-Allow-Credentials: 允许携带Cookie
如果不允许,服务器返回正常的HTTP响应,但是没有任何的CORS相关的头信息,浏览器就会认定,服务器不同意预检请求,因此触发一个错误
如果允许,以后每次浏览器正常的CORS请求,就和普通请求一样了。
具体服务器可以设置一个拦截器
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String originHeader = request.getHeader("Origin");
response.setHeader("Access-Control-Allow-Origin", originHeader);
response.addHeader("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With,accessToken");
response.addHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH");
return true;
}
本文参考
http://www.ruanyifeng.com/blo...
https://www.ruanyifeng.com/bl...
https://juejin.im/post/684490...
重磅资源!!!
关注小白不想当码农微信公众号。
后台回复java核心技术卷关键字领取《java核心技术卷》pdf
回复jvm领取《深入理解Java虚拟机》pdf和《自己动手写jvm》
回复设计模式领取《headfirst设计模式》pdf
回复计算机网络领取《计算机网络自顶向下》pdf
最后
我是不想当码农的小白,平时会写写一些技术博客,推荐优秀的程序员博主给大家还有自己遇到的优秀的java学习资源,希望和大家一起进步,共同成长。
以上内容如有错误,还望指出,感谢
公众号点击交流,添加我的微信,一起交流编程呗!