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和操作结果。审计日志应与业务日志分离存储,并设置严格的读取权限。
全局安全配置优化不是一次性工作,而是需要在每次版本迭代和架构调整后重新审视。框架默认值往往偏向开发便利性而非安全性,只有持续收紧默认行为,才能让应用在面临自动化扫描和定向攻击时具备更强的抗性。把上述配置项落地到项目模板中,让每个新服务从一开始就运行在加固后的基线上,比事后补救要有效得多。
