SpringBoot 之跨域问题
部分参考自:https://www.javaboy.org/2019/0412/springboot-cors.html
同源策略
很多人对跨域有一种误解,以为这是前端的事,和后端没有关系。事实上不是这样的,说到跨域,就不得不说说浏览器的同源策略。同源策略是有NetScape提出的一个著名的安全策略,它是浏览器最核心也是最基本的安全能,现在所有支持JavaScript的浏览器都会使用这个策略。所谓同源是指 协议、域名以及端口要相同。同源策略是基于安全方面的考虑提出来的,这个策略本身是没有问题,但是我们在实际开发中,由于各种原因又经常有跨域的需求,传统的跨域方案是JSONP,JSONP虽然能解决跨域但是有一个很大的局限性,那就是只支持GET请求,不支持其它类型的请求,而今天我们说的CORS(跨域源资源共享)(CORS Cross-origin Resource Sharing) 是一个 W3C标准,它是一份浏览器技术的规范,提供了Web服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略,这是JSONP模板的现代版。
在Spring框架中,对于CORS也提供了相应的解决方案,今天我们就来看看SpringBoot中如何实现CORS。
实践
首先我们创建两个项目,一个项目(springboot-cors1)的端口就设置为默认的8080,另一个(springboot-cors2)端口设置为8081.
在springboot-cors1中定义如下内容:
1 |
|
启动项目。我们接下来把请求页面写在项目springboot-cors2中,(导入jQuery):
classpath:/resources/static/index.html
1 | <!DOCTYPE html> |
启动项目,请求:
我们F12签到springboot-cors2的前端请求页面抛出错误了。No 'Access-Control-Allow-Origin Header is present on the requested resource'
. 因为同源问题,请求无法发送成功。
我们在SpringBoot使用CORS可以在不修改前端的任何代码时,实现跨域,那么接下来我们看看在springboot-cors1中需要如何进行配置。
方式一:
1 |
|
我们可以使用注解@CrossOrigin 注解并指定源来实现跨域,但是这种情况下,如果一个Controller中有很多方法,肯定不可能手动在每一个方法上加注解。所以我们可以将注解加到类上:
1 |
|
此时我们测试,可以发现,可以正常访问了。
但是我们在项目中,肯定不可能将所有的接口都放在一个Controller中,有没有一种方法可以全局配置呢?当然。我们可以通过下面这种方法:
1 |
|
我们可以删除在Controller中使用注解的方式。而是自定义一个配置类并实现WebMvcConfigurer接口,同时重写addCorsMappings方法。如上,我们就可以全局进行配置了。此时我们再次访问,成功。如下:
存在的问题
了解了整个CORS的工作过程之后,我们通过Ajax发送跨域请求,虽然用户体验提高了,但是也有潜在的威胁存在,常见的就是CSRF(Cross-site request forgery)跨站请求伪造。跨站请求伪造也被称为one-click attack 或者 session riding,通常缩写为CSRF或者XSRF,是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法,举个例子:
假如一家银行用以运行转账操作的URL地址如下:
http://icbc.com/aa?bb=cc
,那么,一个恶意攻击者可以在另一个网站上放置如下代码:<img src=”http://icbc.com/aa?bb=cc" > ,如果用户访问了恶意站点,而她之前刚访问过银行不久,登录信息尚未过期,那么她就会遭受损失。
基于此,浏览器在实际操作中,会对请求进行分类,分为简单请求,预先请求,带凭证的请求等,预先请求会首先发送一个options探测请求,和浏览器进行协商是否接受请求。默认情况下跨域请求是不需要凭证的,但是服务端可以配置要求客户端提供凭证,这样就可以有效避免csrf攻击。