同源策略是由 Netscape 提出的一个著名的安全策略,它是浏览器最核心也最基本的安全功能,现在所有支持 JavaScript 的浏览器都会使用这个策略。
所谓同源是指协议、域名以及端口要相同。
同源策略是基于安全方面的考虑提出来的,这个策略本身没问题,但是我们在实际开发中,由于各种原因又经常有跨域的需求。
传统的跨域方案是 JSONP,JSONP 虽然能解决跨域但是有一个很大的局限性,那就是只支持 GET 请求。
而今天我们说的 CORS(跨域源资源共享)(CORS,Cross-origin resource sharing)是一个 W3C 标准,它是一份浏览器技术的规范,提供了 Web 服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略,这是 JSONP 模式的现代版
/hello
,/byebye
@RestController
public class Cors1Controller{
@PostMapping("/hello")
public String hello(){
return "post---hello";
}
@GetMapping("/byebye")
public String byebye(){
return "get---byebye";
}
}
resources/static
目录下创建HTML文件http://localhost:8080/hello
发送请求<div id="app">div>
<input type="button" onclick="btnClick()" value="get_button">
<input type="button" onclick="btnClick2()" value="post_button">
<script>
function btnClick() {
$.get('http://localhost:8080/hello', function (msg) {
$("#app").html(msg);
});
}
function btnClick2() {
$.post('http://localhost:8080/byebye', function (msg) {
$("#app").html(msg);
});
}
script>
Access to XMLHttpRequest at 'http://localhost:8080/hello' from origin 'http://localhost:8081' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
由于同源策略的限制,由8081端口发送的请求无法向8080端口发送。
在暴露接口的一方加上@CrossOrigin注解,避开同源策略。
@RestController
public class HelloController {
//这个注解表示这两个接口接受来自 http://localhost:8081 地址的请求
@CrossOrigin(origins = "http://localhost:8081")
@PostMapping("/hello")
public String hello() {
return "post---hello";
}
@CrossOrigin(origins = "http://localhost:8081")
@GetMapping("/byebye")
public String hello2() {
return "get---byebye";
}
}
这个表示服务端愿意接收来自http://localhost:8081/
的请求,拿到这个信息后,浏览器就不会再去限制本次请求的跨域了。
如果每个Controller上都加这样一个注解,岂不是非常麻烦?
在 Spring Boot 中,还可以通过全局配置一次性解决这个问题,全局配置只需要在SpringMVC配置类中重写 addCorsMappings 方法即可
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8081")
.allowedMethods("*")
.allowedHeaders("*");
}
}
/**
表示本应用的所有方法都会去处理跨域请求
*
表示所有请求方式(GET/POST/PUT/DELETE···
)和请求头可以支持跨域提交, allowedMethods 表示允许通过的请求方式,allowedHeaders 则表示允许的请求头。
经过这样的配置之后,就不必在每个方法上单独配置跨域了。
了解了整个 CORS 的工作过程之后,我们通过 Ajax 发送跨域请求,虽然用户体验提高了,但是也有潜在的威胁存在,常见的就是 CSRF(Cross-site request forgery)跨站请求伪造。跨站请求伪造也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF ,是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法,举个例子:
假如一家银行用以运行转账操作的 URL 地址如下:
http://icbc.com/aa?bb=cc
,那么,一个恶意攻击者可以在另一个网站上放置如下代码:,如果用户访问了恶意站点,而她之前刚访问过银行不久,登录信息尚未过期,那么她就会遭受损失。
基于此,浏览器在实际操作中,会对请求进行分类,分为简单请求,预先请求,带凭证的请求等,预先请求会首先发送一个 options 探测请求,和浏览器进行协商是否接受请求。默认情况下跨域请求是不需要凭证的,但是服务端可以配置要求客户端提供凭证,这样就可以有效避免 csrf 攻击。
参考博客