一、同源策略

​ 同源策略是由 Netscape 提出的一个著名的安全策略,它是浏览器最核心也最基本的安全功能,现在所有支持 JavaScript 的浏览器都会使用这个策略。所谓同源是指协议、域名以及端口要相同。同源策略是基于安全方面的考虑提出来的,这个策略本身没问题,但是我们在实际开发中,由于各种原因又经常有跨域的需求,传统的跨域方案是 JSONP,JSONP 虽然能解决跨域但是有一个很大的局限性,那就是只支持 GET 请求,不支持其他类型的请求,而 CORS(跨域源资源共享)(CORS,Cross-origin resource sharing)是一个 W3C 标准,它是一份浏览器技术的规范,提供了 Web 服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略,这是 JSONP 模式的现代版。在 Spring 框架中,对于 CORS 也提供了相应的解决方案, SpringBoot 中如何实现 CORS。

二、如何出现

启动两个 SpringBoot 项目,分别以 8080 和 8081 端口启动,在其中一个写上如下的 Controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
public class HelloController {

@PostMapping("/hello")
public String hello1() {
return "get hello";
}

@GetMapping("/hello")
public String hello2() {
return "post hello";
}

}

在另一个中写入一个静态页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="jquery-3.5.1.js"></script>
</head>
<body>
<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/hello', function (msg) {
$("#app").html(msg);
});
}
</script>
</body>
</html>

注:记得引入 Jquery

http://localhost:8081/hello.html 点击任何请求:

image-20200820133227549

可以看到此时已经发生跨域问题

三、解决方案

从后端解决,修改 Controller 为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RestController
public class HelloController {

@CrossOrigin(origins = "http://localhost:8081")
@PostMapping("/hello")
public String hello1() {
return "post hello";
}

@CrossOrigin(value = "http://localhost:8081")
@GetMapping("/hello")
public String hello2() {
return "get hello";
}

}

其中 origins 与 value 效果一样,看源码可以知道它们互相成为对方的别名

此时已经不会出现跨域问题

image-20200820134429094

四、加强版解决

此时,在每一个类或者方法上都使用这个注解,法外狂徒张三都觉得这个太麻烦了

只需要配置一个实现 WebMvcConfigurer 配置类,如下:

1
2
3
4
5
6
7
8
public class CORSConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:8081")
.allowedMethods("*")
.allowedHeaders("*");
}
}

注:/** 表示本应用的所有方法都会去处理跨域请求;allowedMethods 表示允许通过的请求数;allowedHeaders 则表示允许的请求头。

五、安全问题

出现了一个王八老本行的问题:通过 Ajax 发送跨域请求,虽然用户体验提高了,但是也有潜在的威胁存在,常见的就是 CSRF(Cross-site request forgery)跨站请求伪造。

一句话:利用我们还在登录的状态,即 Cookie 有效,打开一个正常网站,而这个网站上可能有一个非正常操作 ( 图片,链接等) ,那你就可能已经被攻击。

在信息安全中,我们防御 CSRF 的方法主要是增加 Token,这也是现在大多数防御 CSRF 的方式。

评论