REST服务是否真的需要CSRF防护?JWT认证场景下的疑问
这个问题问得很到位!咱们得先从CSRF攻击的本质和JWT的常见存储方式说起,才能理清风险点和应对方案。
先搞懂CSRF攻击的核心逻辑
CSRF(跨站请求伪造)的本质是:浏览器会自动在请求中携带当前域名下的Cookie。如果后端依赖Cookie识别用户身份,攻击者就能诱导已登录用户访问恶意网站,恶意网站悄悄发起针对你API的请求,浏览器自动带上用户的登录Cookie,后端会误以为是用户本人操作,从而执行恶意行为(比如修改密码、提交敏感数据)。
回到你的JWT场景,风险与否完全取决于你怎么存储和传递JWT:
情况1:JWT存在HttpOnly、Secure的Cookie中(推荐的安全存储方式)
如果你的JWT存在Cookie里,并且设置了HttpOnly(防止XSS脚本窃取)和Secure(仅HTTPS传输),那你确实面临CSRF风险。举个实际攻击场景:
- 用户登录你的系统,浏览器保存了带JWT的Cookie;
- 用户被诱导点击恶意链接,进入攻击者的网站;
- 恶意网站通过JS发起一个POST请求到你的API(比如
/api/user/update-profile); - 浏览器自动把你的域名下的JWT Cookie带过去;
- 后端验证JWT有效,就会执行修改用户信息的操作——这就是典型的CSRF攻击。
这种情况下,必须启用Spring的CSRF防护,而且Angular已经帮你做了大部分工作:Angular会自动从名为XSRF-TOKEN的Cookie中读取令牌,然后在请求头里带上X-XSRF-TOKEN。你只需要在Spring Boot的安全配置中开启CSRF,并配置令牌的存储方式:
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http // 开启CSRF防护,使用Cookie存储令牌,允许前端读取 .csrf(csrf -> csrf .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) ) // 其他认证、授权配置... ; return http.build(); } }
情况2:JWT存在localStorage/sessionStorage或内存中,前端手动在请求头携带
如果你的JWT存在前端的localStorage、sessionStorage里,或者存在内存中,然后前端在每次请求时手动在Authorization头里带上Bearer <token>,那CSRF风险几乎为0。
原因很简单:同源策略限制了恶意网站的JS无法访问你的域名下的localStorage/sessionStorage,而且浏览器不会自动在跨域请求中带上自定义的Authorization头——攻击者没法让浏览器帮他把JWT带到你的API请求里,自然没法伪造用户的请求。
不过这种方式要注意另一个风险:XSS攻击。如果攻击者能在你的页面注入恶意脚本,就能直接读取localStorage里的JWT,然后冒充用户发起请求。所以这种情况下,你需要做好XSS防护(比如对用户输入内容转义、配置CSP内容安全策略等)。
总结一下
- 若用Cookie存储JWT(推荐的安全存储方式,防XSS):必须启用CSRF防护;
- 若用前端存储+自定义请求头带JWT:无需CSRF防护,但要重点防范XSS攻击。
内容的提问来源于stack exchange,提问作者Abhishek Chatterjee

