SpringBoot默认的安全配置只能算基础兜底,很多团队上线后遇到的第一波攻击往往不是来自业务逻辑漏洞,而是框架默认行为被利用。比如错误堆栈暴露内部包名、Actuator端点未授权访问、静态资源目录穿越、Session固定攻击等。这些问题不需要攻击者有多高的技术水平,只要扫描器跑一遍就能发现。真正有效的做法不是堆砌依赖,而是从配置层把默认行为收紧,让框架本身先具备抗侦察和抗自动化攻击的能力。

关闭错误堆栈与异常细节输出

SpringBoot的默认错误处理会返回包含异常类型、堆栈片段和请求路径的JSON或HTML页面。攻击者通过故意构造非法参数,就能获取到内部类名、框架版本甚至SQL片段。优化第一步是在application.yml中明确关闭堆栈输出:

server:
  error:
    include-stacktrace: never
    include-message: never
    include-binding-errors: never
    include-exception: false

同时建议自定义全局异常处理器,统一返回不带敏感信息的错误结构。很多开发者只在Controller层做try-catch,但过滤器链和参数解析阶段抛出的异常依然会走默认处理。正确的做法是实现ErrorController或者使用@RestControllerAdvice配合@ExceptionHandler覆盖Exception.class,返回固定格式的错误码和提示语。生产环境还应将日志级别调整为WARN以上,避免DEBUG日志把请求参数和SQL语句完整记录下来。

收紧Actuator端点暴露策略

Actuator是SpringBoot被利用最频繁的组件。默认情况下health和info端点可能暴露,但如果团队为了调试方便配置了management.endpoints.web.exposure.include=*,就等于把heapdump、env、beans、mappings全部公开。heapdump里经常能提取出数据库密码、Redis密钥和云服务凭证。优化方案是显式指定仅暴露health和info,并关闭敏感端点:

management:
  endpoints:
    web:
      exposure:
        include: health,info
    jmx:
      exposure:
        include: health,info
  endpoint:
    health:
      show-details: never
    env:
      enabled: false
    heapdump:
      enabled: false
    shutdown:
      enabled: false

如果业务确实需要暴露部分运维端点,必须配合Spring Security做路径级鉴权,只允许特定角色访问。同时把Actuator的上下文路径从默认的/actuator改为随机字符串,增加扫描器发现成本。注意修改路径不能替代鉴权,只能作为额外干扰层。

强制HTTPS与安全响应头

SpringBoot内嵌容器默认不强制HTTPS,很多系统在反向代理层做了TLS终止,但应用自身仍然接受明文HTTP请求。如果攻击者能绕过代理直接访问容器端口,通信内容就会被嗅探。配置层面应开启强制跳转:

server:
  port: 8443
  ssl:
    enabled: true
    key-store: classpath:keystore.p12
    key-store-password: changeit
    key-store-type: PKCS12
  http:
    port: 8080

对于无法在应用层配置证书的场景,至少要在代码中增加过滤器,检查X-Forwarded-Proto头,非HTTPS请求直接返回301跳转。安全响应头方面,SpringSecurity提供了默认的headers配置,但很多项目没有引入SpringSecurity。可以自定义一个OncePerRequestFilter统一添加:

response.setHeader("X-Content-Type-Options", "nosniff");
response.setHeader("X-Frame-Options", "DENY");
response.setHeader("X-XSS-Protection", "1; mode=block");
response.setHeader("Referrer-Policy", "strict-origin-when-cross-origin");
response.setHeader("Content-Security-Policy", "default-src 'self'; frame-ancestors 'none'");
response.setHeader("Permissions-Policy", "geolocation=(), microphone=(), camera=()");

这些响应头能阻止浏览器层面的点击劫持、MIME嗅探和部分XSS利用。CSP策略需要根据实际静态资源来源调整,但至少应禁止内联脚本和跨域frame嵌套。

Session安全与Cookie属性加固

SpringBoot默认的Session Cookie没有设置HttpOnly和SameSite属性,这意味着XSS漏洞一旦存在,攻击者可以直接读取会话标识,或者利用跨站请求携带Cookie。配置文件中可以全局指定:

server:
  servlet:
    session:
      cookie:
        http-only: true
        secure: true
        same-site: strict
      timeout: 15m
      tracking-modes: cookie

SameSite设为strict能有效阻断CSRF攻击,但会影响跨站跳转时的会话保持。如果业务有合法的跨站导航需求,可以降级为lax。另外必须禁用URL重写作为Session追踪方式,否则会话ID会出现在日志和浏览器历史中。对于登录成功后的会话,应在代码中调用request.changeSessionId()防止Session固定攻击。如果使用SpringSecurity,它默认会处理这一点,但自定义登录流程需要手动实现。

限制请求体大小与参数复杂度

默认情况下SpringBoot对请求体大小没有严格限制,攻击者可以发送超大JSON或multipart请求导致内存耗尽。配置层面应设置合理的上限:

spring:
  servlet:
    multipart:
      max-file-size: 5MB
      max-request-size: 10MB
server:
  tomcat:
    max-http-form-post-size: 2MB
    max-swallow-size: 2MB
    max-http-header-size: 8KB

除了大小限制,还应对JSON解析深度和集合元素数量做约束。Jackson默认允许无限嵌套,攻击者可以构造深层嵌套对象触发StackOverflow。可以在ObjectMapper中配置:

ObjectMapper mapper = new ObjectMapper();
mapper.getFactory().setStreamReadConstraints(
    StreamReadConstraints.builder()
        .maxNestingDepth(100)
        .maxStringLength(20000)
        .maxNumberLength(1000)
        .build()
);

这些限制能有效防御基于解析器资源消耗的DoS攻击。同时建议在网关或过滤器层增加请求频率限制,单IP每秒请求数超过阈值直接返回429。

静态资源与路径遍历防护

SpringBoot的静态资源映射默认从classpath:/static/、classpath:/public/等目录读取。如果代码中使用了自定义的ResourceHandler并拼接用户输入路径,就可能产生路径遍历漏洞。优化方案是避免手动拼接文件路径,改用Spring提供的ResourceLoader配合Path规范化:

Path basePath = Paths.get(uploadDir).toAbsolutePath().normalize();
Path targetPath = basePath.resolve(fileName).normalize();
if (!targetPath.startsWith(basePath)) {
    throw new SecurityException("Invalid file path");
}

对于静态资源目录,建议关闭目录列表功能,并确保所有文件读取都经过规范化校验。如果业务需要文件下载,应使用白名单机制限制允许的扩展名和目录范围,而不是简单过滤../字符串。

依赖版本与自动化漏洞扫描

安全配置优化不能只停留在代码层,依赖管理同样关键。SpringBoot每年都会发布多个安全修复版本,很多漏洞的利用条件就是旧版本中的默认行为。建议在CI流程中集成依赖检查工具,定期扫描pom.xml或build.gradle中的已知CVE。同时关注Spring官方发布的安全公告,对于标记为Critical的漏洞应在24小时内完成升级。生产环境的SpringBoot版本不应停留在EOL阶段,否则安全补丁将不再提供。

日志脱敏与审计追踪

安全配置优化的最后一个环节是日志。很多系统在记录请求日志时会把Authorization头、Cookie、身份证号、手机号等敏感信息完整写入文件。攻击者一旦获取日志读取权限,就能直接拿到用户凭证。建议在日志框架层面实现脱敏规则,对匹配正则的字段自动替换为掩码。同时开启访问日志的审计功能,记录关键操作的时间、用户、IP和操作结果。审计日志应与业务日志分离存储,并设置严格的读取权限。

全局安全配置优化不是一次性工作,而是需要在每次版本迭代和架构调整后重新审视。框架默认值往往偏向开发便利性而非安全性,只有持续收紧默认行为,才能让应用在面临自动化扫描和定向攻击时具备更强的抗性。把上述配置项落地到项目模板中,让每个新服务从一开始就运行在加固后的基线上,比事后补救要有效得多。