前言
提起跨域,可能大多数猿们都不陌生,在工作中多多少少都有碰到,现在比较主流的跨域模式有cors和jsonp:
-
jsonp:利用浏览器对script资源的引用没有同源规则的限制,通过动态插入script标签的方式(其实就是跨域限制的一个漏洞),将地址指向第三方的地址,比如
<script src="http://www.test.com/test?a=1&b=2"></script>
,同时提供一个回调函数来处理第三方响应的json数据callback({"a": 1, "b": 2})
。当然,客户端可以随意定制回调函数来处理返回数据,主需要跟服务端提前约定好即可。注:需要注意的是:jsonp的跨域模式其实就是一种脚本注入的行为,它可能会造成一些不安全的行为。而且,它只支持get请求,不支持post等其它类型的http请求,而且不能解决不同域的两个页面之间互相进行JavaScript调用的问题。
cors:
Corss-Origin Resource Sharing
,跨域资源共享,它是一个W3C标准,允许浏览器向跨源服务器发起XMLHttpRequest
请求。
本文将讲解简单请求的cors跨域服务端如何做?安全校验如何做?
简单请求的cors跨域
注:什么叫简单请求?
浏览器将cors请求分为两类:简单请求(simple request)和非简单请求(not-so-simple request),只要同时满足以下条件的就属于简单请求,否则都属于非简单需求:
- 请求方法是
HEAD
,GET
,POST
之一;- HTTP的头信息不超出以下几种字段:
- Accept
- Accept-Language
- Content-Language
- Content-Type:只能取三个值
application/x-www-form-urlencoded
、multipart/form-data
、text/plain
- Last-Event-ID
当然浏览器对于这两种请求的处理也是有区别的,非简单请求浏览器会增加一次http查询请求(预检请求),先询问服务器当前请求域名是否在服务器的许可名单之中以及可以使用哪些http动词和头信息字段,只有得到正确的答复,浏览器才会发起一次正式的
XMLHttpRequest
请求,否则报错。
对于简单请求的cors跨域,具体的流程如下:
-
浏览器发起请求,在请求header中增加
Origin
字段,表示本次请求来自哪个源,具体的请求header如下所示:Accept:*/* Accept-Language:zh-CN,zh;q=0.9 Connection:keep-alive Origin:https://miao.test.com User-Agent:Mozilla/5.0...
-
服务端接收到请求后,判断
Origin
指定的源,如果在允许调用的范围呢,服务端正常返回,需要注意的是,服务端在返回时需要在header中设置Access-Control-Allow-Origin
字段,浏览器会判断该字段是否包含请求中的Origin
值,如果包含,响应正确,否则,浏览器会抛出错误,正确响应header如下所示:Access-Control-Allow-Credentials:true Access-Control-Allow-Origin:https://miao.test.com Access-Control-Expose-Headers: FooBar Content-Type: text/html; charset=utf-8
上文响应header中有3个与cors请求相关的字段:
-
Access-Control-Allow-Origin
:必须要有的字段,它的值可以是请求header的Origin
的值,也可以是*
(表示接受任何域的请求),需要注意的是,如果为*
的话,会有一系列的安全问题,建议不要这么做; -
Access-Control-Allow-Credentials
:可选字段,表示是否允许发送cookie,true表示允许,另外该字段的值只能设置为true,如果服务端不需要浏览器发送cookie,删除该字段就可以。需要注意的是,如果需要发送cookie还需要前端配合的,前端必须要在ajax请求中打开withCredentials
属性; -
Access-Control-Expose-Headers
:可选字段,可以通过该字段指定获取响应header中的某个字段的值。
-
知道流程之后,那么对于cors跨域的安全怎么做也就一目了然了,可以直接判断请求的Origin
是否在允许跨域的域名白名单内,如果在,则服务端允许返回正确响应,否则,服务端拦截,响应异常。接下来给个简单的例子吧,一看就会用:
安全校验Interceptor
服务端Controller处理
服务端的处理方式与正常同源请求响应一样,不需要像jsonp那样需要包装响应数据:
@RequestMapping(value = "/test.json", method = RequestMethod.POST)
public void test(HttpServletRequest request, ModelMap modelMap) {
try {
modelMap.put("success", true);
modelMap.put("data", "test");
} catch (Exception e) {
modelMap.put("success", false);
modelMap.put("errCode", 1001);
modelMap.put("errMsg", "系统异常");
}
}
到这里,简单请求的cors模式跨域就大致介绍完了,非简单请求大家在工作中其实不太常遇到,在这里我就不做详细的介绍了,以后遇到了再做相关介绍。就让我小小的放飞下自己~~~~~~