# 跨域的本质
相信大家在做web系统开发的时候,都遇到过前端页面访问另一个服务器而非本服务器从而遭遇的跨域问题。跨域是个很常见的问题,虽然在web系统中的解决方式很简单,加一段耳熟能详的代码,或者一个注解,或者在某个框架中配置点什么就能解决,但是不少开发者并没有对跨域有全面的系统性的认知。
# 1、什么是跨域
# 浏览器的同源策略Same-origin Policy
如果两个url的协议、域名或ip、端口都相同,即在浏览器中被视为两者同源。 下表给出了相对http://store.company.com/dir/page.html同源检测的示例:
URL | 结果 | 说明 |
---|---|---|
http://store.company.com/dir2/other.html | 成功 | |
http://store.company.com/dir/inner/another.html | 成功 | |
https://store.company.com/secure.html | 失败 | 不同协议 ( https和http ) |
http://store.company.com:81/dir/etc.html | 失败 | 不同端口 ( 81和80) |
http://news.company.com/dir/other.html 失败 | 不同域名 ( news和store ) |
- DOM同源策略:禁止对不同源的页面的DOM进行操作,主要包括iframe、canvas之类的。不同源的iframe禁止数据交互的,含有不同源数据的canvas会受到污染而无法进行操作。
- XmlHttpRequest同源策略:禁止不同源的AJAX请求,主要用来防止CSRF攻击
# 2、CORS说明
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。也就是说CORS是为了解决跨源访问问题的一套机制。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
# 3、跨域演示
设有两个服务器A和B,A的页面调用A的接口,没有问题; 但是A的页面调用B的接口,将会产生跨域问题。进入A的index页面
两个按钮的对应的触发代码
function testA(){
$.get("/testA", function(data){
alert("Data Loaded: " + data);
});
}
function testB(){
$.get("localhost:8081/testB", function(data){
alert("Data Loaded: " + data);
});
}
2
3
4
5
6
7
8
9
10
点击左边按钮,对应后台代码为:
@GetMapping("/testA")
public String test(){
System.out.println("访问A网站");
return "访问A网站";
}
2
3
4
5
大体意思就是从源localhost:8080发出的请求localhost:8081/testB被CORS跨资源共享机制阻止了。因为端口不同。
# 4、跨域引起的问题
# 那么为什么会防范跨域这个机制呢,因为如果允许跨域会发生诸多的安全问题。如CSRF攻击:
一个网站用户Bob可能正在浏览聊天论坛,而同时另一个用户Alice也在此论坛中,并且后者刚刚发布了一个具有Bob银行链接的图片消息。 设想一下,Alice编写了一个在Bob的银行站点上进行取款的form提交的链接,并将此链接作为图片src。如果Bob的银行在cookie中保存他的授权信息,并且此cookie没有过期,那么当Bob的浏览器尝试装载图片时将提交这个取款form和他的cookie,这样在没经Bob同意的情况下便授权了这次事务。
# 5、跨域CORS头信息
CORS头信息 | 说明 |
---|---|
Access-Control-Allow-Origin | 指示请求的资源能共享给哪些域 可以是具体的域名或者*表示所有域。 |
Access-Control-Allow-Credentials | 指示当请求的凭证标记为 true 时 是否响应该请求。 |
Access-Control-Allow-Headers | 用在对预请求的响应中, 指示实际的请求中可以使用哪些 HTTP 头。 |
Access-Control-Allow-Methods | 指定对预请求的响应中, 哪些 HTTP 方法允许访问请求的资源。 |
Access-Control-Expose-Headers | 指示哪些 HTTP 头的名称能在响应中列出。 |
Access-Control-Max-Age | 指示预请求的结果能被缓存多久。 |
Access-Control-Request-Headers | 用于发起一个预请求, 告知服务器正式请求会使用那些 HTTP 头。 |
Access-Control-Request-Method | 用于发起一个预请求, 告知服务器正式请求会使用哪一种 HTTP 请求方法。 |
Origin | 指示获取资源的请求是从什么域发起的 |