Spring框架CSRF防护深度指南
一、Spring Security默认防护机制
1.1 核心工作原理
Spring Security从4.0版本开始默认启用CSRF防护,通过同步令牌模式(Synchronizer Token Pattern)实现:
- 生成随机令牌存储于Session
- 将令牌注入表单隐藏字段或请求头
- 验证每个POST/PUT/DELETE请求的令牌有效性
<!-- 自动生成的隐藏字段 -->
<input type="hidden" name="_csrf" value="4bfd1575-3ad1-4d21-96c7-4ef2d9f83d92"/>
1.2 请求处理流程
二、配置与自定义
2.1 基础配置
Java Config方式:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf() // 默认启用
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.authorizeRequests()
.antMatchers("/public/**").permitAll()
.anyRequest().authenticated();
}
}
XML Config方式:
<http>
<csrf token-repository-ref="csrfTokenRepository"/>
<intercept-url pattern="/admin/**" access="hasRole('ADMIN')"/>
</http>
<beans:bean id="csrfTokenRepository"
class="org.springframework.security.web.csrf.CookieCsrfTokenRepository"/>
2.2 高级自定义
令牌存储方式:
// 会话存储(默认)
.csrfTokenRepository(HttpSessionCsrfTokenRepository.INSTANCE)
// Cookie存储(推荐)
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
// 自定义存储
.csrfTokenRepository(new CustomCsrfTokenRepository())
请求头携带方式:
// 客户端设置(Axios示例)
axios.defaults.headers.common['X-CSRF-TOKEN'] = '${_csrf.token}';
2.3 排除特定路径
http
.csrf()
.ignoringAntMatchers("/api/v1/public/**", "/health-check")
三、REST API防护方案
3.1 推荐实现方式
双重提交Cookie模式:
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
请求头携带示例:
GET /api/data HTTP/1.1
Host: example.com
Cookie: XSRF-TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
X-XSRF-TOKEN: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
3.2 Angular集成示例
// app.module.ts
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { XsrfInterceptor } from './xsrf.interceptor';
@NgModule({
imports: [HttpClientModule],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: XsrfInterceptor,
multi: true
}
]
})
export class AppModule {}
四、常见问题解决
4.1 403错误排查
检查项:
- 确认请求方法为POST/PUT/DELETE
- 验证请求头/参数包含有效令牌
- 检查Cookie策略(SameSite设置)
- 确认未错误配置csrf().disable()
调试技巧:
// 启用详细日志
logging.level.org.springframework.security.web.csrf=DEBUG
4.2 多页面应用适配
Thymeleaf集成:
<form th:action="@{/transfer}" method="post">
<input type="hidden" th:name="${_csrf.parameterName}"
th:value="${_csrf.token}"/>
<!-- 其他表单字段 -->
</form>
JSP集成:
<input type="hidden"
name="${_csrf.parameterName}"
value="${_csrf.token}"/>
4.3 移动端适配
原生App集成:
- 会话Cookie自动管理
- 显式传递X-CSRF-TOKEN头
- 使用Token绑定机制:
.csrf()
.csrfTokenRequestHandler(new ServerCsrfTokenRequestHandler() {
@Override
public void handle(HttpServletRequest request,
HttpServletResponse response,
CsrfToken token) {
if ("POST".equals(request.getMethod())) {
response.setHeader("X-CSRF-TOKEN", token.getToken());
}
}
})
五、生产环境最佳实践
5.1 安全增强配置
令牌轮换策略:
.csrf()
.csrfTokenRepository(new DefaultCsrfTokenRepository() {
@Override
public CsrfToken generateToken(HttpServletRequest request) {
CsrfToken token = super.generateToken(request);
if (isLoginRequest(request)) {
return token; // 登录时不轮换
}
return new DefaultCsrfToken(
token.getHeaderName(),
token.getParameterName(),
UUID.randomUUID().toString());
}
});
请求频率限制:
.sessionManagement()
.maximumSessions(1)
.maxSessionsPreventsLogin(true)
.and()
.and()
.requestCache()
.requestCache(new NullRequestCache()) // 防止缓存CSRF令牌
5.2 监控与审计
关键指标收集:
- CSRF验证失败次数
- 令牌生成频率
- 会话并发数
- 异常请求来源分布
审计日志示例:
{
"timestamp": "2023-08-01T14:30:00Z",
"event": "CSRF_VALIDATION_FAILED",
"user": "anonymous",
"path": "/api/transfer",
"client_ip": "192.168.1.100",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
}
5.3 灾难恢复方案
紧急禁用流程:
- 特征分析:识别攻击特征(高频403错误)
- 配置回滚:临时禁用CSRF防护
- 流量清洗:配合WAF过滤恶意请求
- 策略恢复:问题修复后逐步启用防护
配置回滚示例:
// 仅在紧急情况下使用
http
.csrf().disable() // 临时禁用
.authorizeRequests()
.anyRequest().permitAll();
六、合规性要求
6.1 标准映射表
规范/标准 | 相关条款 | 实施要求 |
---|---|---|
PCI DSS | 6.5.10 | 关键支付接口实施CSRF防护 |
GDPR | 32(1)(b) | 用户数据操作保护 |
ISO 27001 | A.14.2.5 | Web应用安全控制 |
NIST 800-53 | SC-8, SC-20 | 传输层保护与验证机制 |
OWASP ASVS | 4.3.1, 4.3.2 | CSRF防护验证 |
使用Spring框架CSRF防护机制相关配置策略是实际生产环境实践安全的有效途径。