Spring对CSRF的防范
Posted 响应式编程
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring对CSRF的防范相关的知识,希望对你有一定的参考价值。
这篇基本上是Spring Security Reference关于 CSRF 部分的一个笔记,只是记录一下核心逻辑。其它很多细节还是要参考官方文档。
什么是 CSRF
跨站请求伪造。经典场景是:
1)受害者首先登录了银行网站
2)用户没有 longout 的情况下
3)用同一个浏览器访问了“坏”网站
4)“坏”网站有一个向银行网站提交业务请求的页面
5)诱使用户发送这个请求。
实际上利用有 XSS 漏洞,完全可以无需受害者参与利用 javascript 而自动触发第 4 第 5 步。
这个场景背后的逻辑:
归根结底,这种 CSRF 的问题是因为早期的cookie设计过于简单,没有和现代浏览器同源策略等安全机制同步造成的。
解决方案
一个是主流的“Synchronizer Token Pattern”方法,另一个是渐成主流的“SameSite Attribute”。
1)SameSite Attribute
这个方式实施和理解比较容易,我们先说。
服务端利用 cookie 的 SameSite 属性可以禁止浏览器从外部站点发送请求时带上 cookie。比如下面的 cookie 就不会被放在由在第三方网页发起而目标是银行网站的请求上。这就自然解决了上面的 CSRF 的问题。SameSite还可设为Strict。
Set-Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly; SameSite=Lax
2)Synchronizer Token Pattern
这个解决办法的原理是对来自浏览器的请求我们都回送一个随机数,下次浏览器再请求业务时需要在 header 里或者表单里带上这个随机数。这个随机数就是 csrf token。Spring Security就是采用的这个方式。
这个办法之所以能防范 CSRF,是因为 sessionId 来自 cookie,而 csrf token 来自 header 或者 form。相当于分别在两条不同的路径上传递。
Spring Security 模块生成 csrf token 后可放在两个地方。Spring 默认的,随机数与 sessionId 关联,放在 session 里。另一个方式:随机数放在 cookie 里。
a) 基于 Session 保存 csrf token
与 session 关联比较容易理解,下次浏览器发送请求过来,服务端就可以从 header 或 form 里取出来的 csrf token 与 session 中的随机数相比较来进行判断。
b) 基于 Cookie 保存 csrf token
通过 cookie 保存 csrf 是怎么回事呢?如果 csrf token 通过 cookie 发送给浏览器,那这个随机数不就跟 JSESSIONID 一样了会被浏览器自动传回到服务器了吗?
是的,这个通过cookie传给浏览器的 csrf token 一定会被浏览器传回给服务器,我们也正是利用这一点“保存”了 csrf token。之所以使用基于 cookie 的方式,是因为要针对前后端分离的情形让前端可以使用 javascript 获得 csrf token,并把这个 token 作为下次请求的 header 参数或者 form 参数传递给服务端。服务端所要做的就是通过对比来自 cookie 和 header/form 这两条路径的 csrf token 来做出该请求是否为CSRF的判断。
下面代码设置使用 cookie 保存csrf token,使用 cookie 传递 token 需要把 cookie 的 HttpOnly 属性设置为 false,以便让 javascript 能读到此值。
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
http
.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
);
}
}
以上是关于Spring对CSRF的防范的主要内容,如果未能解决你的问题,请参考以下文章