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框架中最常见的安全攻击面,每一项都能直接落地到现有项目。安全配置不是一次性工作,需要结合业务场景持续调整。建议在每次上线前使用自动化扫描工具验证配置是否生效,并定期审查安全头、会话策略和依赖版本。