如何为应用的所有GET请求启用CSRF保护?
嘿,这个问题问得很到位——很多人容易忽略GET请求的CSRF风险,但同时也容易踩URL暴露token的坑。先给你梳理下思路和解决方案:
首先得明确:HTTP规范定义GET是「安全且幂等」的方法,也就是它只应该用来获取资源、不应该执行任何修改系统状态的操作(比如提交数据、删除内容、修改配置)。如果你的GET请求只是做纯查询,其实不需要额外加CSRF防护——因为CSRF攻击的核心危害是攻击者诱导用户执行未授权的状态变更,纯查询操作即使被攻击,最多是泄露数据(那属于XSS或其他权限控制问题,不是CSRF的范畴)。
但如果你的GET请求确实涉及敏感操作(比如某些特殊场景下的状态变更,或者返回高度敏感的用户数据),那确实需要防护,接下来是安全的实现方式:
最稳妥的做法是把所有涉及状态变更的GET请求改成POST/PUT/DELETE这类非GET方法。这样不仅符合HTTP规范,还能直接复用你已经实现的POST请求CSRF防护逻辑,同时避免URL暴露token、浏览器缓存GET请求导致的误操作(比如用户误点书签触发敏感操作)。
如果因为业务限制必须保留GET方法并加CSRF防护,那绝对不要把token放在URL参数里——URL会被浏览器缓存、存在历史记录、书签中,还可能被服务器日志记录,风险极高。推荐用以下方式:
自定义HTTP请求头传递token
在AJAX请求中添加一个自定义请求头(比如X-CSRF-Token),把token放在头里传递,这样不会出现在URL中,也不会被常规的日志或缓存记录。
修改你的AJAX代码如下:
$.ajax({ url: "${pageContext.request.contextPath}/Someprocess.do", type: "GET", headers: { "X-CSRF-Token": "${CSRF_TOKEN}" }, // 把token放在请求头里 data: {param1: request.param1, param2: "param2"}, dataType: "json", success: function (data) { response(data); } });
然后修改你的javax.servlet.Filter逻辑:
- 对于GET请求,从
HttpServletRequest.getHeader("X-CSRF-Token")获取token - 对比session中存储的token值,校验通过才允许请求继续
给存储CSRF token的Cookie设置SameSite=Strict或SameSite=Lax属性,这样浏览器会限制跨站请求自动携带该Cookie,能大幅降低CSRF攻击的可能性。不过这只是辅助措施,不能替代token校验——因为同域内的恶意脚本(比如XSS注入的脚本)依然可以获取Cookie并添加到请求头里,所以还是要结合自定义头的token校验。
- 不要在GET请求中执行任何写操作,这是HTTP设计的基本原则,也是避免CSRF风险的核心。
- 确保你的CSRF token是每个用户会话唯一、不可预测的,并且过期后会重新生成,避免被复用。
内容的提问来源于stack exchange,提问作者Re Viki

