Java Web 应用的 CSRF 攻击原理与防御策略:保护用户会话安全
Java Web 应用的 CSRF 攻击原理与防御策略:保护用户会话安全
在当今的互联网时代,Java Web 应用广泛应用于各个领域。然而,随着应用的普及,安全问题日益凸显,其中 CSRF(Cross - Site Request Forgery,跨站请求伪造)攻击就是一个不容忽视的威胁。本文将深入探讨 Java Web 应用中 CSRF 攻击的原理,并提供有效的防御策略,以保护用户会话安全。
一、CSRF 攻击原理
CSRF 攻击是一种利用用户身份认证信息,未经用户授权而执行非用户本意操作的攻击方式。攻击者诱导已登录 Web 应用的用户访问恶意页面,借助用户的身份向目标应用发送请求。
例如,假设用户在浏览某银行网站后未退出,又访问了一个恶意网站。恶意网站中包含一段代码,自动向银行网站发送转账请求。由于浏览器会自动附带银行网站的 Cookie,银行网站会认为该请求是用户发起的合法操作,从而执行转账。
<!-- 恶意页面代码示例 -->
<form id="csrfForm" action="http://bank.example.com/transfer" method="POST">
<input type="hidden" name="toAccount" value="attackerAccount">
<input type="hidden" name="amount" value="1000">
</form>
<script>
document.getElementById("csrfForm").submit();
</script>
二、防御策略
(一)CSRF Token
CSRF Token 是防御 CSRF 攻击的常用方法。服务器在生成页面时,为每个请求生成一个唯一的 Token,并将其存储在服务器端,同时将 Token 作为隐藏字段嵌入到 HTML 表单或作为请求头的一部分。
- 生成 Token :可以使用随机数生成器或加密算法生成 Token。
import java.security.SecureRandom;
import java.util.Base64;
public class CSRFTokenGenerator {
private static final SecureRandom random = new SecureRandom();
public static String generateToken() {
byte[] tokenBytes = new byte[32];
random.nextBytes(tokenBytes);
return Base64.getUrlEncoder().withoutPadding().encodeToString(tokenBytes);
}
}
- 验证 Token :在处理请求时,服务器端从请求中获取 Token,并与服务器端存储的 Token 进行比较。如果两者不匹配,则拒绝该请求。
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CSRFTokenFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String clientToken = httpRequest.getHeader("X-CSRF-Token");
String serverToken = (String) httpRequest.getSession().getAttribute("CSRF_TOKEN");
if (clientToken == null || !clientToken.equals(serverToken)) {
httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid CSRF Token");
return;
}
chain.doFilter(request, response);
}
@Override
public void destroy() {}
}
在 JSP 页面中,将 Token 作为隐藏字段添加到表单中:
<form action="transfer" method="POST">
<input type="hidden" name="CSRF_TOKEN" value="${sessionScope.CSRF_TOKEN}">
<!-- 其他表单字段 -->
</form>
(二)SameSite Cookie 属性
SameSite Cookie 属性可以有效防止 CSRF 攻击。通过设置 SameSite 属性,可以限制 Cookie 在跨站请求时的行为。
- SiteSame=Lax :在大部分情况下,仅在相同站点内发送 Cookie。但在导航到目标页面的 GET 请求(如链接点击)时,会发送 Cookie。
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
public class SameSiteCookieSetter {
public static void setSameSiteLaxAttribute(HttpServletResponse response, String cookieName, String cookieValue) {
Cookie cookie = new Cookie(cookieName, cookieValue);
cookie.setHttpOnly(true); // 防止客户端脚本访问 Cookie
cookie.setSecure(true); // 仅在 HTTPS 连接下发送 Cookie
cookie.setSameSite("Lax");
response.addCookie(cookie);
}
}
- SameSite=Strict :仅在相同站点内发起的请求才会发送 Cookie。与 SameSite=Lax 相比,对安全性要求更高,但可能会对用户体验产生一定影响。
(三)验证 HTTP 请求头
可以检查 HTTP 请求头中的 “Referer” 字段,确保请求来自合法的来源。
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public classer ReferFilter implements Filter {
private static final String ALLOWED_REFERER = "http://your-allowed-domain.com";
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String referer = httpRequest.getHeader("Referer");
if (referer == null || !referer.startsWith(ALLOWED_REFERER)) {
httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid Referer");
return;
}
chain.doFilter(request, response);
}
@Override
public void destroy() {}
}
需要注意的是,这种方式可能受到一些代理或浏览器设置的影响,导致 Referer 字段丢失或被篡改。
通过对 CSRF 攻击原理的深入理解以及合理运用上述防御策略,可以有效地保护 Java Web 应用的用户会话安全,降低安全风险,保障用户的利益和应用的正常运行。在实际开发中,应根据应用的具体需求和场景,综合运用多种防御手段,构建坚固的安全防线。
- 点赞
- 收藏
- 关注作者
评论(0)