SpringBoot开发,接口请求,如何增加CSRF防护?
发布于 作者:苏南大叔 来源:程序如此灵动~

对于"用户接口请求/表单提交"来说,实际上存在着普遍的csrf
攻击问题。这个问题是如何产生的呢?应该如何防范呢?基于springboot
的项目里面,如何简单的增加相关防范代码呢?这就是本文所试图解决的问题。

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。测试环境:win10
,openjdk@23.0.2
,IntelliJ IDEA 2024.3.4.1
,maven@3.3.2
,spring boot@2.5.4
,java@17
,mysql@5.7.26
。
csrf基本原理
csrf
的基本原理是这样的:
csrf攻击
跨站请求伪造(Cross-Site Request Forgery
,简称 CSRF
)是一种攻击方式,攻击者通过伪造用户的请求,利用用户在目标网站的身份进行未授权的操作。CSRF
攻击通常发生在用户已经登录目标网站并且会话仍然有效的情况下。
对于被攻击的网站来说,其实并没有太大的过错,接口都是可以正常调用的,甚至登陆session
检测也是存在的。但是,它是如何被利用的呢?
第三方网站知晓这些网站接口的调用方式后,就可以在访问第三方网站的时候,自动执行这些接口。由于浏览器的机制,【某些特殊情况下】会自动带上正常的cookie
,从而导致接口端误认为这个是正常的用户行为。
csrf
攻击行为和正常的用户行为,唯一不同的地方就是:referer
!来源页不同。所以,如果服务器端对referer
做严格检测的话,应该是可以区分是否是用户正常行为的。
自动带上cookie
这件事情,和浏览器有关。很古老版本的浏览器中,都是自动无条件带上cookie
的。而目前的浏览器中,只有一些服务器上设置有问题的情况下,才会自动带上cookie
。所以,原来普遍存在的csrf
漏洞,目前变成了:个别情况下,才会有漏洞存在。转变的根本原因,就是:浏览器转变了对与cookie
是否提交的默认处理方式。
csrf防护
防护措施,除了常规的referer
检测外,最常见的方案就是增加csrf token
。实际上就是先由服务器端生成一个临时的随机字符串,保存在客户端。随着接口的提交,服务端要检测csrf token
是否原装。非原装或者错误的值,就认为这是个非法请求。
对于仅返回数据这种并不修改数据的接口,一遍不做csrf
检测,因为没有太大的必要。判断标准是依据接口行为来判断的,是否涉及数据的修改就是最好的标准。
目前还有一种方式,就是设置cookie
的samesite
属性。当然,默认值就是比较安全的lax
。所以,如果设置了,可能会出问题。不设置,反而是安全的。
springboot与csrf
spring
系列代码中,spring security
自带csrf
防护。然而,由于其天生的复杂性,太难以控制。所以苏南大叔并不建议使用spring security
自带的csrf
防护。
在本文中,就是使用传统概念上的csrf
防护逻辑(并不是框架里面带的)。服务器端生成随机字符串,保存在session
中。然后传递到客户端代码中,客户端再向服务端做请求的时候,在合适的时机,服务端再次检测这个随机字符串。
基础代码
项目代码比较多,所以本文仅叙述关键代码。其它代码可以参考以前的文章:
- https://newsn.net/say/springboot.html
- https://newsn.net/say/springboot-hot.html
- https://newsn.net/say/springboot-model.html
- https://newsn.net/say/springboot-entity.html
- https://newsn.net/say/springboot-session.html
- https://newsn.net/say/springboot-jpa.html
实际上主要的思路,还是session
。登陆成功后,显示/success
页面,该页面上,增加对/user
接口的各种调用。
生成csrf token
在LoginController.java
文件里面,把随机字符串(uuid
)写入到session
里面。并且传递到模版里面。\src\main\java\com\example\demo\controller\LoginController.java
:

传递csrf token
src/main/resources/templates/success.html
:

验证csrf token
src/main/java/com/example/demo/controller/UserController.java
:

结语
本文描述的是不使用spring security
,而是使用传统思路解决csrf
问题。更多苏南大叔的java
相关文章,可以参考下面的链接:


