SpringBoot自带的安全机制常被误解为“默认关闭”,实际上它内置了多条防线,但需要开发者显式开启或正确配置才能真正抵御攻击。最常见的攻击面集中在会话固定、点击劫持、内容类型嗅探、跨站脚本反射以及HTTP响应头缺失。下面直接给出可落地的配置方案,并解释每项配置具体拦截哪一类攻击。
启用安全响应头拦截点击劫持与MIME嗅探点击劫持攻击利用iframe将你的页面嵌入恶意站点,诱导用户误操作。SpringBoot Security模块默认会添加X-Frame-Options: DENY,但如果你没有引入Spring Security,仅靠SpringBoot自动配置不会输出该头。最直接的方式是在配置类中注册SecurityFilterChain,并开启headers配置。同时,X-Content-Type-Options: nosniff可以阻止浏览器根据内容猜测MIME类型,降低恶意脚本执行风险。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class WebSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.headers(headers -> headers
.frameOptions(frame -> frame.deny())
.contentTypeOptions(contentType -> contentType.nosniff())
.xssProtection(xss -> xss.disable())
);
return http.build();
}
}
这里关闭了X-XSS-Protection,因为现代浏览器已废弃该头,保留反而可能引入额外的过滤漏洞。重点放在frameOptions和contentTypeOptions上,这两个头能立即降低中低级别的自动化攻击成功率。
强制HTTPS并开启HSTS防止降级攻击如果你的服务已经部署了HTTPS,必须开启Strict-Transport-Security。很多项目只做了HTTP到HTTPS的跳转,却忽略了HSTS,导致用户在第一次访问或中间人场景下仍可能被降级到HTTP。SpringBoot中可以通过配置强制https,并添加HSTS头。
http
.requiresChannel(channel -> channel.anyRequest().requiresSecure())
.headers(headers -> headers
.httpStrictTransportSecurity(hsts -> hsts
.includeSubDomains(true)
.maxAgeInSeconds(31536000)
)
);
requiresSecure会强制所有请求走HTTPS,而HSTS头告诉浏览器在未来一年内只通过HTTPS访问该域名及其子域,从根源上阻断SSL剥离攻击。注意,如果你的服务还运行在HTTP环境下,不要开启此配置,否则用户将无法访问。
会话管理加固防止会话固定攻击SpringBoot默认的会话管理在用户登录后不会更换Session ID,这为会话固定攻击提供了机会。攻击者先诱导用户使用一个已知的Session ID登录,之后攻击者利用该ID冒充用户。修复方法是在登录成功时迁移会话,并限制会话并发。
http
.sessionManagement(session -> session
.sessionFixation(fixation -> fixation.migrateSession())
.maximumSessions(1)
.maxSessionsPreventsLogin(false)
);
migrateSession会在认证成功后创建新的Session ID,保留原会话中的属性,使攻击者手中的旧ID失效。maximumSessions限制同一账号只能有一个活跃会话,防止账号共享或会话劫持后的横向扩展。如果业务需要多端登录,可以调整该值,但至少应开启sessionFixation。
CSRF防护的正确启用与API场景处理Spring Security的CSRF防护默认开启,但很多前后端分离项目因为接口返回403就粗暴地禁用了它。对于纯API服务,如果前端使用Token认证而非Cookie,可以安全禁用CSRF;但如果你的前端依赖Cookie中的Session,必须保留CSRF Token机制。推荐的做法是保留CSRF,并为前端提供获取Token的接口。
http
.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
);
CookieCsrfTokenRepository将CSRF Token写入Cookie,前端读取后放入请求头X-XSRF-TOKEN中。这种方式不需要服务端存储Token,适合无状态API。注意withHttpOnlyFalse允许前端脚本读取该Cookie,如果前端不读取,可以保持HttpOnly开启,但需要后端在页面渲染时注入Token。
跨域配置避免过度开放CORS很多开发者遇到跨域问题就直接返回Access-Control-Allow-Origin: *,这等于把接口暴露给任何恶意网站。SpringBoot中应精确配置允许的源、方法和头。
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/")
.allowedOrigins("https://your-frontend-domain.com")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("Content-Type", "X-XSRF-TOKEN")
.allowCredentials(true)
.maxAge(3600);
}
}
allowedOrigins不要使用通配符,明确列出前端域名。allowCredentials为true时,Access-Control-Allow-Origin不能为*,否则浏览器会拒绝响应。对于非浏览器客户端,CORS不生效,因此攻击者仍可能直接调用接口,所以CORS只是浏览器层面的限制,不能替代认证和授权。
内置错误处理防止信息泄露默认的SpringBoot错误页面会返回详细的堆栈信息、请求路径和异常类型,攻击者可以利用这些信息探测内部结构。生产环境必须关闭详细错误信息。
server:
error:
include-message: never
include-stacktrace: never
include-exception: false
同时,自定义错误控制器可以返回统一的JSON结构,避免暴露技术细节。对于API接口,建议使用@ControllerAdvice统一处理异常,只返回必要的错误码和用户可读信息。
依赖版本与自动配置的持续更新SpringBoot内置的安全机制依赖于底层框架版本。例如,旧版本的Tomcat或Jackson可能存在已知漏洞,即使你的代码没有安全问题,也会被扫描器标记。保持SpringBoot版本更新是成本最低的防护手段。在pom.xml中定期检查依赖更新,并使用dependency-check插件扫描已知CVE。
org.owasp dependency-check-maven 8.4.0 check
该插件会在构建阶段扫描项目依赖,发现已知漏洞时构建失败。结合CI流程,可以强制开发者在引入高风险依赖时立即处理。
内置过滤器的执行顺序与自定义过滤器插入SpringBoot的Security过滤器链有严格的顺序,如果你添加了自定义过滤器,必须明确插入位置。例如,认证过滤器应在AuthorizationFilter之前执行,否则请求可能被提前拒绝。使用addFilterBefore或addFilterAfter控制顺序。
http
.addFilterBefore(new CustomAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
错误的过滤器顺序可能导致安全配置被绕过。例如,将自定义的日志过滤器放在SecurityContextHolderFilter之前,可能导致未认证请求也能访问受保护资源。建议在添加自定义过滤器时,先查看Spring Security默认过滤器链的顺序表,确认插入点。
针对文件上传与路径遍历的额外配置SpringBoot默认不限制上传文件大小和类型,攻击者可以上传恶意脚本或超大文件耗尽磁盘。在application.yml中设置上传限制,并在业务代码中校验文件扩展名和内容类型。
spring:
servlet:
multipart:
max-file-size: 5MB
max-request-size: 20MB
文件存储时不要直接使用用户提供的文件名,应生成随机文件名并存储到非Web可访问目录。对于需要下载的文件,通过接口读取并设置正确的Content-Disposition,避免路径遍历漏洞。
日志脱敏与审计安全配置不仅是拦截攻击,还要记录攻击行为。SpringBoot默认的日志可能包含敏感信息,如Session ID、Token、用户输入。在日志配置中增加脱敏规则,并对关键操作记录审计日志。
logging:
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} - %msg%n"
level:
org.springframework.security: DEBUG
将Spring Security的日志级别调为DEBUG可以记录认证失败、授权拒绝等事件,但生产环境应使用INFO或WARN,避免日志量过大。对于认证成功和失败事件,可以自定义AuthenticationSuccessHandler和AuthenticationFailureHandler记录用户、IP、时间等信息。
以上配置覆盖了SpringBoot框架中最常见的安全攻击面,每一项都能直接落地到现有项目。安全配置不是一次性工作,需要结合业务场景持续调整。建议在每次上线前使用自动化扫描工具验证配置是否生效,并定期审查安全头、会话策略和依赖版本。
