Web 安全是应用安全的基石。OWASP Top 10 中绝大多数漏洞与 Web 层密切相关。Spring Security 提供了丰富的安全功能,但默认配置往往不够——需要针对具体场景进行纵深防御配置。
1. 安全响应头(Security Headers)
1.1 核心响应头速查
| 响应头 | 用途 | 风险 |
|---|---|---|
Content-Security-Policy | 限制资源加载来源 | XSS、数据注入 |
X-Frame-Options | 防止页面被嵌入 iframe | Clickjacking |
X-Content-Type-Options | 禁止 MIME 嗅探 | 文件类型混淆攻击 |
Referrer-Policy | 控制 Referrer 信息 | 敏感 URL 泄露 |
Permissions-Policy | 限制浏览器 API | 摄像头/位置等隐私 |
Strict-Transport-Security | 强制 HTTPS | SSL Strip 攻击 |
1.2 Spring Security 配置
@Configuration
@EnableWebSecurity
public class SecurityHeadersConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.headers(headers -> headers
// Content Security Policy
.contentSecurityPolicy(csp -> csp
.policyDirectives(
"default-src 'self'; " +
"script-src 'self' 'unsafe-inline' https://cdn.example.com; " +
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; " +
"img-src 'self' data: https://images.example.com; " +
"font-src 'self' https://fonts.gstatic.com; " +
"connect-src 'self' https://api.example.com; " +
"frame-ancestors 'none'; " +
"form-action 'self'; " +
"base-uri 'self';"
)
)
// 不再支持 iframe 嵌入
.frameOptions(frame -> frame.deny())
// 禁止 MIME 类型嗅探
.contentTypeOptions(contentType -> contentType.enable())
// Referrer 策略
.referrerPolicy(referrer -> referrer
.policy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)
)
// Permissions Policy
.permissionsPolicy(permissions -> permissions
.policy("camera=(), microphone=(), geolocation=(), payment=()")
)
// HSTS
.httpStrictTransportSecurity(hsts -> hsts
.includeSubDomains(true)
.maxAgeInSeconds(31536000) // 1 year
.preload(true)
)
);
return http.build();
}
}
1.3 报告模式(Report-Only)
// 先使用 report-only 模式,观察 CSP 违规报告,确认无误后再强制启用
http.headers(headers -> headers
.contentSecurityPolicy(csp -> csp
.policyDirectives("default-src 'self'; report-uri /csp-report")
.reportOnly() // 只报告,不拦截
)
);
2. CSRF 防护
2.1 CSRF 原理
用户已登录 bank.com(Cookie 中有 session)
│
├── 访问 bank.com/transfer?to=attacker&amount=10000 ← 正常操作
│
└── 访问恶意网站 evil.com
└── 页面自动提交表单:
<form action="https://bank.com/transfer" method="POST">
<input name="to" value="attacker">
<input name="amount" value="10000">
</form>
<script>document.forms[0].submit()</script>
→ 浏览器自动带上 bank.com 的 Cookie
→ 请求验证通过(因为 Cookie 是有效的)
2.2 Spring Security CSRF 配置
@Configuration
public class CsrfConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf
// SPA/API 场景: 使用 Cookie 存储 Token
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
// 或: Header 存储(前后端分离)
// .csrfTokenRepository(new HttpSessionCsrfTokenRepository())
// 忽略某些路径(如 Webhook)
.ignoringRequestMatchers("/webhook/**", "/api/public/**")
// 部分请求使用 CSRF
.requireCsrfProtectionMatcher(
new AndRequestMatcher(
CsrfFilter.DEFAULT_CSRF_MATCHER,
new NegatedRequestMatcher(
new AntPathRequestMatcher("/api/**", "GET")
)
)
)
);
return http.build();
}
}
2.3 前后端分离的 CSRF
// 后端: 启用 Cookie 传输 CSRF Token
@Bean
public CsrfTokenRepository csrfTokenRepository() {
CookieCsrfTokenRepository repository = CookieCsrfTokenRepository.withHttpOnlyFalse();
repository.setCookieName("XSRF-TOKEN");
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
// 前端 (Axios): 自动从 Cookie 读取并发送到 Header
axios.defaults.xsrfCookieName = 'XSRF-TOKEN';
axios.defaults.xsrfHeaderName = 'X-XSRF-TOKEN';
// 更现代的做法: 如果 API 使用 JWT(无 Cookie Session),可以完全禁用 CSRF
// 因为 JWT 不会自动随请求发送,攻击者无法获取
@Configuration
@Profile("api-only")
public class ApiSecurityConfig {
@Bean
public SecurityFilterChain apiChain(HttpSecurity http) throws Exception {
http
.securityMatcher("/api/**")
.csrf(csrf -> csrf.disable()) // API 无 Cookie Session,无需 CSRF
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.oauth2ResourceServer(oauth2 ->
oauth2.jwt(jwt -> jwt.decoder(jwtDecoder())));
return http.build();
}
}
3. CORS 配置
3.1 CORS 原理
浏览器同源策略:
- 相同: protocol + host + port
- 不同源访问 → 浏览器拦截
CORS 流程:
1. 预检请求: OPTIONS /api/data
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-Custom-Header
2. 服务器响应:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Max-Age: 3600
3. 正式请求发送
3.2 Spring Security CORS 配置
@Configuration
public class CorsConfig {
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
// 明确指定允许的源,不要泛化为 *
configuration.setAllowedOrigins(Arrays.asList(
"https://app.example.com",
"https://admin.example.com"
));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(Arrays.asList(
"Authorization", "Content-Type", "X-Requested-With", "X-Trace-Id"
));
configuration.setExposedHeaders(Arrays.asList("X-Total-Count", "X-Trace-Id"));
configuration.setAllowCredentials(true); // 允许 Cookie
configuration.setMaxAge(3600L); // 预检缓存 1 小时
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", configuration);
return source;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.cors(cors -> cors.configurationSource(corsConfigurationSource()));
return http.build();
}
}
CORS 安全红线:
- ❌ 不要
setAllowedOrigins(Arrays.asList("*"))+setAllowCredentials(true)同时设置 - ❌ 不要基于请求的
Origin动态反射(除非严格校验域名) - ✅ 使用明确的域名白名单
- ✅ 生产环境设置
Vary: Origin
4. XSS 防护
4.1 输入过滤与输出编码
@Component
public class XssFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
XssHttpServletRequestWrapper wrappedRequest =
new XssHttpServletRequestWrapper((HttpServletRequest) request);
chain.doFilter(wrappedRequest, response);
}
}
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
return value != null ? HtmlUtils.htmlEscape(value) : null;
}
}
4.2 富文本过滤
@Service
public class HtmlSanitizerService {
private final PolicyFactory policy = new HtmlPolicyBuilder()
.allowElements("p", "br", "strong", "em", "u", "h1", "h2", "h3", "ul", "ol", "li", "a")
.allowAttributes("href").onElements("a")
.requireRelNofollowOnLinks()
.toFactory();
public String sanitize(String html) {
return policy.sanitize(html);
}
}
4.3 Spring 自动转义
@Controller
public class CommentController {
@GetMapping("/comment")
public String comment(Model model) {
// Thymeleaf 自动转义: ${comment} → HTML 实体编码
// 仅明确需要时才使用 th:utext (unescaped text)
model.addAttribute("comment", userInput); // 自动安全
return "comment";
}
}
5. 会话安全
5.1 会话固定攻击防护
@Configuration
public class SessionSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.sessionManagement(session -> session
.sessionFixation().migrateSession() // 登录后更换 Session ID
.maximumSessions(1) // 单点登录
.maxSessionsPreventsLogin(false) // 后登录者踢掉前者
.expiredUrl("/login?expired")
);
return http.build();
}
}
5.2 Cookie 安全属性
@Configuration
public class CookieConfig {
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("SESSION");
serializer.setCookiePath("/");
serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$");
serializer.setUseSecureCookie(true); // 仅 HTTPS 传输
serializer.setSameSite("Strict"); // SameSite 严格模式
return serializer;
}
}
6. 安全审计与监控
@Component
public class SecurityAuditListener {
private static final Logger auditLog = LoggerFactory.getLogger("AUDIT");
@EventListener
public void onAuthenticationSuccess(AuthenticationSuccessEvent event) {
auditLog.info("LOGIN_SUCCESS|user={}|ip={}",
event.getAuthentication().getName(),
getClientIp());
}
@EventListener
public void onAuthenticationFailure(AbstractAuthenticationFailureEvent event) {
auditLog.warn("LOGIN_FAILURE|user={}|reason={}|ip={}",
event.getAuthentication().getName(),
event.getException().getMessage(),
getClientIp());
}
}
延伸阅读
- Java 安全认证与授权 — OAuth2 与 JWT 深入实现
- 监控系统架构设计 — 安全监控体系设计
- 信息安全与云安全 — 安全专题总览
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。