Spring Boot 的自动配置机制极大地简化了开发,但这也是安全问题的重灾区。很多团队只关注业务代码的安全,却忽略了框架本身默认开启的组件、端点和管理接口,这些地方一旦暴露,攻击者甚至不需要SQL注入就能直接拿下服务器内存数据或执行远程命令。安全自动配置加固,不是去写一堆自定义过滤器,而是从Spring Boot的Auto Configuration机制入手,堵住那些“默认开启但你根本不知道”的缺口。
关闭或限制Actuator端点暴露Spring Boot Actuator是最大的信息泄露源。默认情况下,/actuator/health和/actuator/info可能被暴露,但如果引入了完整的Actuator Starter,很多敏感端点会被自动注册。加固的第一步是显式配置哪些端点可以对外,哪些只能内部访问。在application.yml中,不要只配置include,要同时配置exclude,并强制要求所有端点默认禁用,按需开启。
management:
endpoints:
web:
exposure:
include: "health,info"
exclude: "env,beans,threaddump,heapdump,mappings"
endpoint:
health:
show-details: never
env:
enabled: false
beans:
enabled: false
heapdump:
enabled: false
这里的关键点是heapdump端点。它默认可能被自动配置加载,攻击者通过下载堆转储文件可以分析出内存中的密码、Token、密钥等敏感数据。即使你配置了exclude,也要在endpoint级别显式禁用,因为某些版本中exclude只影响发现页面,端点本身仍可访问。另外,/actuator路径本身应该通过security配置进行访问控制,不要仅依赖Web容器层面的IP白名单,因为代理和CDN可能导致IP伪造绕过。
禁用自动配置中不必要的Web安全特性Spring Security的自动配置会生成默认的用户名和随机密码打印在日志中,这在生产环境是灾难性的。很多开发者以为改了默认密码就安全了,但实际上控制台日志可能被集中采集到ELK或Splunk,任何有日志查看权限的人都能拿到初始凭证。必须显式禁用Security的自动UserDetailsService配置,并提供自定义的认证机制。
spring:
security:
user:
name: ""
password: ""
仅仅置空还不够,因为某些条件装配仍然会触发默认的InMemoryUserDetailsManager。更彻底的做法是在配置类中排除UserDetailsServiceAutoConfiguration:
@SpringBootApplication(exclude = {
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration.class
})
同时要检查是否自动引入了Spring Security的CSRF保护。对于纯API服务,CSRF是多余的,但Spring Boot自动配置默认开启。如果不显式关闭,所有POST/PUT/DELETE请求都需要携带CSRF Token,这会导致移动端或第三方调用失败,而开发者往往为了快速解决直接禁用整个Security配置,反而造成更大的安全缺口。正确做法是保留Security框架,仅针对特定路径关闭CSRF。
Session创建策略的强制收敛Spring Boot自动配置的Session策略是IF_REQUIRED,这意味着只要某个请求触发了HttpSession的创建,容器就会生成JSESSIONID。在RESTful API中,这会导致无状态服务意外地变成有状态,还可能引发Session固定攻击。更危险的是,Spring Session自动配置如果检测到Redis等中间件,会自动将Session持久化到共享存储,一旦攻击者通过其他漏洞注入恶意Session属性,整个集群都会受影响。
server:
servlet:
session:
tracking-modes: cookie
cookie:
http-only: true
secure: true
same-site: strict
spring:
session:
store-type: none
对于纯无状态API,直接设置store-type为none,彻底禁用Spring Session的自动配置。如果业务确实需要Session,必须将cookie的SameSite设置为Strict,并开启HttpOnly和Secure标志。同时检查是否有自动配置的SessionRegistry,它会将所有登录用户的Session缓存在内存中,大量并发登录时可能导致内存溢出。
数据源和JPA的自动配置风险Spring Boot的DataSource自动配置会根据classpath中的驱动自动创建数据源,但连接池的默认配置往往过于宽松。HikariCP虽然性能优秀,但默认的connection-timeout、idle-timeout和max-lifetime可能不适合生产环境,更重要的是,自动配置不会强制开启连接验证,导致从连接池中取出的连接可能已经被数据库端关闭,引发异常后重试机制可能暴露错误信息。
spring:
datasource:
hikari:
connection-test-query: "SELECT 1"
validation-timeout: 3000
max-lifetime: 1800000
leak-detection-threshold: 60000
jpa:
show-sql: false
open-in-view: false
properties:
hibernate:
hbm2ddl:
auto: validate
open-in-view是Spring Boot JPA自动配置中最常被忽视的安全和性能陷阱。它默认开启,意味着视图渲染完成前数据库连接一直保持,这不仅导致连接池耗尽,还会让事务边界模糊,攻击者可以通过构造慢请求长时间占用数据库连接。show-sql在生产环境必须关闭,否则SQL语句会输出到日志,包含敏感查询条件。hbm2ddl.auto绝对不能设置为update或create-drop,只能使用validate或none,防止自动修改数据库结构。
Jackson和消息转换器的反序列化安全Spring Boot自动配置了Jackson作为JSON序列化工具,但默认的ObjectMapper配置启用了Default Typing相关的多态类型处理,这是反序列化漏洞的根源。攻击者可以通过构造特殊的JSON payload,利用多态类型解析触发任意类加载和代码执行。必须显式禁用默认类型处理,并限制可反序列化的类白名单。
@Configuration
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
return builder -> {
builder.featuresToDisable(
com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS,
com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
);
builder.featuresToEnable(
com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_INVALID_SUBTYPE
);
};
}
}
更重要的是,检查项目中是否自动引入了Jackson的JAXB注解支持或Scala模块,这些模块扩展了多态类型处理的范围,增加了攻击面。如果不需要XML格式的请求,应该在WebMvcConfigurer中限制消息转换器只保留JSON,移除XML和protobuf等自动配置的转换器。
Thymeleaf和模板引擎的自动配置加固Spring Boot对Thymeleaf的自动配置默认开启了模板缓存和SpringEL表达式,但同时也默认允许在模板中执行OGNL或SpEL表达式。如果业务中有用户输入被直接拼接到模板中(即使不是模板文件,而是通过Thymeleaf处理邮件模板等场景),就可能触发表达式注入。必须显式限制模板引擎的表达式执行能力。
spring:
thymeleaf:
cache: true
mode: HTML
encoding: UTF-8
servlet:
content-type: text/html
enabled: true
check-template-location: true
reactive:
max-chunk-size: 8192
更彻底的做法是使用Thymeleaf的SpringSecurityDialect时,确保不将原始用户输入作为模板变量传递。如果使用了其他模板引擎如Freemarker,同样需要检查其自动配置是否允许执行任意Java方法,Freemarker的ObjectWrapper默认配置可能允许模板中调用Runtime.exec(),必须设置为BeansWrapper的简单模式。
DevTools和热重载的自动配置在生产环境的残留Spring Boot DevTools的自动配置包含远程调试和远程更新功能,如果生产环境的依赖中意外包含了DevTools(常见于构建工具配置错误),应用启动时会自动开启远程调试端口和HTTP远程重启端点。这相当于给攻击者留了一个后门。必须在生产构建中排除DevTools依赖,并在配置中显式禁用它。
spring:
devtools:
restart:
enabled: false
livereload:
enabled: false
remote:
secret: ""
检查项目的Maven或Gradle配置,确保DevTools的scope为runtime且optional为true,或者在生产profile中排除该依赖。同时要扫描classpath中是否存在spring-boot-devtools的jar包,因为某些传递依赖可能意外引入。
内嵌Tomcat/Undertow的容器级安全配置Spring Boot自动配置的内嵌容器默认会暴露Server头信息,显示具体的容器类型和版本号,这为攻击者提供了精准打击的依据。同时,默认的HTTP连接器配置允许TRACE和OPTIONS等HTTP方法,这些方法可能被利用进行跨站追踪攻击或信息探测。
server:
error:
include-stacktrace: never
include-message: never
include-binding-errors: never
tomcat:
accesslog:
enabled: true
pattern: "%h %l %u %t \"%r\" %s %b %D"
max-days: 30
max-http-form-post-size: 2MB
connection-timeout: 5000
对于错误处理,Spring Boot的自动配置会返回详细的异常堆栈信息,这在开发环境有用,但生产环境必须全部关闭。include-message设为never后,客户端不会看到任何异常消息,防止信息泄露。同时要限制POST表单的大小,防止拒绝服务攻击。内嵌容器的最大线程数和连接数也需要根据实际负载调整,默认的200线程在攻击场景下可能很快耗尽。
自动配置的CORS策略收紧Spring Boot如果检测到Spring Web依赖,会自动配置CORS,但默认的CorsFilter是宽松的,允许所有来源、所有方法和所有头部。很多开发者为了前后端分离开发方便,直接使用@CrossOrigin("*")注解,这个配置会被自动扫描并生效。生产环境必须覆盖这个自动配置,明确指定允许的源和方法。
@Configuration
public class CorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/")
.allowedOrigins("https://your-domain.com")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("Authorization", "Content-Type")
.allowCredentials(true)
.maxAge(3600);
}
};
}
}
特别注意allowCredentials(true)不能与allowedOrigins("*")同时使用,这是浏览器安全策略明确禁止的,但Spring Boot自动配置不会检查这个冲突,导致配置无效时开发者往往不知情。另外,如果使用了Spring Security,CORS配置必须在Security过滤链之前生效,否则OPTIONS预检请求会被Security拦截返回401。
日志框架的自动配置安全Spring Boot默认使用Logback,自动配置会加载classpath下的logback-spring.xml或logback.xml。如果配置不当,日志中可能记录请求参数、响应体、认证头等敏感信息。更严重的是,Logback的自动重载配置功能默认开启,攻击者如果能通过其他漏洞修改日志配置文件(如路径穿越),就可以注入恶意的日志Appender,实现远程代码执行。必须关闭自动扫描重载功能。
logging:
level:
root: WARN
org.springframework: WARN
org.hibernate: ERROR
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
file:
name: /var/log/app.log
max-size: 100MB
max-history: 7
在logback-spring.xml中,显式设置scan="false",禁止运行时扫描配置文件变化。同时,日志输出格式中不要包含%mdc或%X,因为MDC中可能存储了用户ID、Session ID等敏感上下文信息。如果必须使用MDC进行链路追踪,要在日志输出前对敏感字段做脱敏处理。
自动配置的缓存和调度任务安全Spring Boot对@EnableCaching和@EnableScheduling的自动配置会创建线程池和缓存管理器。默认的线程池大小是1,但在高并发场景下开发者往往会调大,却没有配置拒绝策略和队列容量,导致任务堆积内存溢出。缓存方面,自动配置的ConcurrentMapCacheManager是无界的,攻击者可以通过构造大量不同的缓存键填满JVM堆内存。
spring:
task:
scheduling:
pool:
size: 4
thread-name-prefix: scheduled-
execution:
pool:
core-size: 8
max-size: 16
queue-capacity: 100
keep-alive: 60s
thread-name-prefix: async-
cache:
type: caffeine
caffeine:
spec: maximumSize=500,expireAfterWrite=600s
将缓存类型从默认的Simple改为Caffeine,并设置最大容量和过期时间。对于异步任务执行器,必须限制队列容量,防止任务无限排队。同时,调度任务的执行时间如果超过调度间隔,默认的调度器会启动新线程执行,可能导致任务并发执行引发数据竞争,需要配置spring.task.scheduling.pool.size并配合@Async注解使用独立的线程池。
Spring Boot的安全自动配置加固不是一次性工作,而是需要在每次版本升级时重新审视。新版本可能会引入新的自动配置类,或者修改现有配置的默认值。建议在CI/CD流水线中加入Spring Boot配置审计步骤,使用spring-boot-actuator的configprops端点(仅内部开放)定期导出所有自动配置项,与安全基线进行比对。真正的安全不在于写了多少自定义代码,而在于你关闭了多少不需要的默认功能。
