CSRF与SPA:Cookie安全配置及CSRF风险判定咨询
一、当前配置下是否存在CSRF漏洞?
从你给出的Cookie配置来看,accessToken和refreshToken都设置了SameSite=Strict、HttpOnly、Secure,这种配置已经能有效抵御绝大多数CSRF攻击:
- SameSite=Strict会阻止第三方网站发起的跨站请求携带这些Cookie(比如恶意网站通过表单提交、AJAX请求你的后端接口);
- HttpOnly避免了XSS攻击窃取token;
- Secure确保Cookie仅在HTTPS下传输。
安全人员指出的“未做CSRF防护”可能是对SameSite Cookie防护能力的误解,或是考虑到旧浏览器(如IE)不支持SameSite属性的兼容场景。但就当前主流浏览器环境而言,你的核心CSRF风险已经被覆盖。
二、为何SameSite(Strict)看似未生效?
你测试的两个场景都是符合SameSite=Strict规则的正常行为,并非失效:
1. 前端与Swagger UI互相同步认证
如果Swagger UI和你的前端/后端属于同站(Same Site)(比如同属example.com域名下的子域名,如app.example.com和api.example.com),浏览器会判定为同站请求,SameSite=Strict的Cookie会正常发送。这是同站场景下的预期行为,不属于跨站请求,所以SameSite规则不会拦截。
2. 点击外部链接跳转至前端仍保持登录
SameSite=Strict仅阻止第三方网站发起的跨站请求(如恶意网站主动发起的POST请求),但允许用户主动点击链接发起的顶级导航(top-level navigation)携带Cookie。当你点击邮件中的链接跳转到前端时,是用户主动触发的页面跳转,浏览器会发送SameSite=Strict的Cookie,这是正常的登录态保持逻辑,并非SameSite失效。
三、SPA场景下的CSRF防护逻辑
不同于服务端渲染(SSR)把CSRF Token嵌入页面的方式,SPA的防护核心是让前端在请求时携带一个后端颁发的、与Cookie绑定的Token,后端验证两者的一致性:
1. 基础方案:Cookie + 请求头Token
- 后端步骤:
- 用户登录成功后,除了返回HttpOnly的accessToken/refreshToken,额外颁发一个非HttpOnly的CSRF Token Cookie(设置SameSite=Strict、Secure、Path=/);
- 后端所有受保护接口验证请求头(如
X-XSRF-TOKEN)中的Token与Cookie中的CSRF Token是否一致。
- 前端步骤:
- 通过
document.cookie读取CSRF Token(因为是非HttpOnly); - 用Axios全局配置,在所有请求的请求头中添加
X-XSRF-TOKEN字段,值为读取到的CSRF Token:axios.defaults.headers.common['X-XSRF-TOKEN'] = document.cookie.match(/XSRF-TOKEN=([^;]+)/)[1];
- 通过
2. Spring Boot适配方案
Spring Boot 2.2+内置了CSRF防护支持,对于SPA场景,可以配置CsrfTokenRepository将CSRF Token存储在Cookie中,并允许前端通过请求头获取验证:
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf(csrf -> csrf .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) ); } }
这种配置会自动生成非HttpOnly的XSRF-TOKEN Cookie,前端只需读取该Cookie并在请求头中携带X-XSRF-TOKEN即可。
3. 防护核心逻辑
CSRF攻击的本质是利用用户的登录态(Cookie)发起未授权请求,而防护的核心是让后端能够区分用户主动发起的请求和第三方网站伪造的请求:通过要求请求携带一个只有前端能获取到的Token(与Cookie绑定),第三方网站无法获取该Token,也就无法伪造合法请求。
内容的提问来源于stack exchange,提问作者Adam Ostrožlík

