本文详解Java中CSRF漏洞的修复方法。首先分析仅校验Referer头的局限性及代码缺陷,随后提供基于Synchronizer Token Pattern的标准修复方案。通过生成、校验Token机制,有效防止跨站请求伪造攻击,保障Web应用安全。
CSRF漏洞修复效果预览
修复后的系统能够有效拦截来自非本站域的恶意请求。当攻击者尝试伪造表单提交时,服务器会因Token缺失或校验失败而拒绝处理,返回非法请求提示。这种机制确保了只有经过授权且来源合法的请求才能执行敏感操作。

修复前的风险分析与代码缺陷
在修复CSRF(跨站请求伪造)漏洞时,许多开发者会尝试通过校验HTTP请求头中的Referer字段来限制来源。虽然这是一种思路,但原文提供的Java Servlet代码存在严重的安全隐患和逻辑错误。
第1步:分析Referer校验的局限性
原文代码尝试通过检查request.getHeader("Referer")来验证请求来源。这种方法存在以下致命缺陷:
- 可被伪造:攻击者可以通过工具(如Burp Suite)轻易修改
Referer头,使其看起来像来自受信任的域名。 - 隐私保护:现代浏览器在HTTPS跳转到HTTP时,或者用户通过隐私模式访问时,可能会丢弃
Referer头,导致正常用户请求被误杀。 - 硬编码风险:代码中硬编码了域名列表(如
"localhost"),缺乏灵活性,且无法适应多域名或子域名切换的场景。
第2步:识别原文代码的逻辑错误
原文提供的Java代码存在语法和逻辑问题,无法直接运行:
- 循环条件缺失:
for (int i = 0; i语句不完整,缺少循环终止条件。 - 逻辑冗余:使用
key布尔变量判断域名匹配,逻辑复杂且易出错。 - 安全性不足:仅依赖
Referer无法从根本上解决CSRF问题。
因此,我们需要采用更安全的Synchronizer Token Pattern(同步器令牌模式)来彻底修复该漏洞。
标准CSRF修复方案:Token机制
CSRF攻击的核心在于攻击者利用用户已登录的Cookie发送恶意请求。修复的关键在于:服务器为每个用户会话生成一个唯一的、不可预测的Token,并在所有敏感表单中嵌入该Token。服务器在处理请求时,必须校验该Token的有效性。
第1步:生成并存储CSRF Token
在用户登录或访问敏感页面时,服务器应生成一个随机Token,并将其存储在用户的Session中。同时,将该Token嵌入到HTML表单的隐藏字段中。
package com.example.csrf;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import java.util.UUID;public class CsrfTokenServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 获取或创建Session HttpSession session = request.getSession(); // 2. 生成唯一的CSRF Token String csrfToken = UUID.randomUUID().toString(); // 3. 将Token存入Session session.setAttribute("_csrf", csrfToken); // 4. 将Token嵌入到表单的隐藏字段中,供前端提交时使用 response.setContentType("text/html;charset=UTF-8"); response.getWriter().write(""); response.getWriter().write(""); response.getWriter().write(""); }} 此步骤确保了每个用户会话拥有独立的Token,攻击者无法预测其他用户的Token值。
第2步:在服务器端校验Token
在处理POST请求时,Servlet必须从请求参数中获取Token,并与Session中存储的Token进行比对。如果两者不一致或Token缺失,则视为CSRF攻击。
package com.example.csrf;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;public class CsrfProcessServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 获取Session HttpSession session = request.getSession(false); if (session == null) { response.getWriter().write("非法请求:无Session"); return; } // 2. 从Session中获取预期的Token String expectedToken = (String) session.getAttribute("_csrf"); // 3. 从请求参数中获取提交的Token String submittedToken = request.getParameter("_csrf"); // 4. 校验Token是否匹配 if (expectedToken == null || !expectedToken.equals(submittedToken)) { response.getWriter().write("非法请求:CSRF Token校验失败"); return; } // 5. Token校验通过,执行业务逻辑 response.getWriter().write("成功读到合法数据"); // 注意:每次成功后,应销毁当前Token并生成新的Token,防止重放攻击 session.invalidate(); // 简单示例中直接使Session失效,实际项目中应生成新Token }} 此步骤是防御CSRF的核心。即使攻击者诱使用户点击恶意链接,由于无法获取用户Session中存储的Token,攻击者的请求将被服务器拒绝。
图片验证与操作核对
在完成上述代码部署后,开发者应进行以下验证:
- 正常流程验证:访问生成Token的页面,检查HTML源码中是否包含隐藏的
_csrf字段。提交表单后,服务器应返回“成功读到合法数据”。(参考图片1:CSRF防护成功拦截非法请求的界面反馈) - 攻击模拟验证:使用Burp Suite或其他工具拦截请求,尝试修改或移除
_csrf参数。服务器应返回“非法请求:CSRF Token校验失败”。(参考图片1:CSRF防护成功拦截非法请求的界面反馈) - 跨域验证:尝试从另一个域名下的页面发起请求,即使该页面能获取到Token(如通过XSS漏洞),由于Token与Session绑定,且通常配合SameSite Cookie属性使用,攻击仍会失败。
问题与调整
问题1:Token校验失败,正常用户无法提交
表现:用户提交表单时,服务器返回“非法请求”。
原因:可能是Session超时导致Token丢失,或者前端表单中未正确嵌入Token。
解决方法:检查Session配置,确保session.setAttribute("_csrf", csrfToken)在doGet中正确执行。同时检查前端HTML源码,确认存在且值正确。
问题2:多标签页操作导致Token冲突
表现:用户在多个标签页同时操作,后打开的标签页提交失败。
原因:每次请求后session.invalidate()导致Session失效,其他标签页的Token失效。
解决方法:不要直接使Session失效,而是生成新的Token并更新Session中的Token值,同时更新前端表单中的Token值。这称为“Token轮换”机制。
总结
修复Java中的CSRF漏洞,最可靠的方法是采用Synchronizer Token Pattern。通过为每个会话生成唯一的Token,并在服务器端严格校验,可以有效防止跨站请求伪造攻击。相比仅校验Referer头,Token机制具有更高的安全性和灵活性。开发者应确保Token的生成、存储、嵌入和校验环节完整无误,并处理好Session管理和Token轮换等细节问题。
以上就是Java CSRF漏洞修复的详细内容,更多关于CSRF防护、Web安全最佳实践的资料请关注本站其它相关文章!
