Spring Boot Actuator 暴露敏感端点的安全加固方案
大家好,今天我们来聊聊Spring Boot Actuator的安全加固,重点关注如何保护那些可能暴露敏感信息的端点。Actuator为我们提供了监控和管理Spring Boot应用的能力,但如果配置不当,它也会成为安全漏洞的入口。
Actuator 简介
Spring Boot Actuator是一个强大的工具,可以帮助你监控和管理你的应用程序。它提供了一系列的端点,用于暴露应用的内部状态、配置信息、健康状况等。
常见的Actuator端点包括:
| 端点 | 描述 | 默认暴露情况 |
|---|---|---|
/health |
显示应用程序的健康状况。 | 公开 |
/info |
显示应用程序的构建信息、版本号等。 | 公开 |
/metrics |
显示应用程序的各种指标,例如JVM内存使用情况、HTTP请求统计等。 | 公开 |
/env |
显示应用程序的环境变量和系统属性。敏感信息可能泄露! | 私有 |
/configprops |
显示应用程序的所有配置属性。敏感信息可能泄露! | 私有 |
/beans |
显示应用程序中定义的所有Spring Beans。 | 私有 |
/mappings |
显示应用程序的所有请求映射。 | 私有 |
/threaddump |
显示应用程序的线程转储。 | 私有 |
/heapdump |
生成应用程序的堆转储。 | 私有 |
/loggers |
获取和修改应用程序的日志级别。 | 私有 |
/auditevents |
显示应用程序的审计事件。 | 私有 |
/httptrace |
显示最近的HTTP请求和响应。 | 私有 |
默认情况下,/health和/info是公开的(可以通过HTTP请求直接访问),其他的端点都是私有的,需要认证才能访问。但是,如果你的配置不当,可能会意外地将敏感端点暴露给未经授权的用户。
风险分析
未加保护的Actuator端点可能导致以下安全风险:
- 敏感信息泄露:
/env、/configprops等端点可能暴露数据库密码、API密钥等敏感信息。 - 信息收集: 攻击者可以通过
/beans、/mappings等端点了解应用程序的内部结构和配置,为进一步攻击做准备。 - 拒绝服务(DoS):
/heapdump等端点可能消耗大量资源,导致应用程序崩溃。 - 恶意配置修改:
/loggers端点允许修改日志级别,可能被用于隐藏攻击行为。
安全加固方案
以下是一些加固Actuator安全性的方案,可以根据你的实际需求选择合适的组合:
1. 禁用不必要的端点
最简单的安全措施是禁用你不需要的端点。这可以通过在application.properties或application.yml文件中设置management.endpoint.<endpoint>.enabled=false来实现。
例如,禁用/env和/configprops端点:
management.endpoint.env.enabled=false
management.endpoint.configprops.enabled=false
或者,使用YAML格式:
management:
endpoint:
env:
enabled: false
configprops:
enabled: false
2. 使用Spring Security进行认证和授权
Spring Security是保护Actuator端点最常用的方法。你需要添加Spring Security依赖到你的项目中:
Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Gradle:
implementation 'org.springframework.boot:spring-boot-starter-security'
然后,你需要配置Spring Security来保护Actuator端点。以下是一个基本的配置示例:
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.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/actuator/**").hasRole("ACTUATOR")
.anyRequest().permitAll()
)
.httpBasic();
return http.build();
}
}
这个配置做了以下事情:
- 禁用了CSRF保护(Actuator端点通常不需要CSRF保护)。
- 要求访问
/actuator/**下的所有端点都需要ACTUATOR角色。 - 允许访问所有其他端点。
- 使用HTTP Basic认证。
你还需要配置一个用户,并赋予其ACTUATOR角色。这可以通过在application.properties或application.yml文件中配置spring.security.user.name、spring.security.user.password和spring.security.user.roles来实现。
例如:
spring.security.user.name=actuator
spring.security.user.password=password
spring.security.user.roles=ACTUATOR
或者,使用YAML格式:
spring:
security:
user:
name: actuator
password: password
roles: ACTUATOR
更细粒度的授权控制:
如果需要更细粒度的控制,可以为不同的Actuator端点配置不同的角色。例如,只有管理员才能访问/heapdump端点。
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.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/actuator/health", "/actuator/info").permitAll()
.requestMatchers("/actuator/heapdump").hasRole("ADMIN")
.requestMatchers("/actuator/**").hasRole("ACTUATOR")
.anyRequest().permitAll()
)
.httpBasic();
return http.build();
}
}
在这个例子中,/health和/info端点不需要认证,/heapdump端点需要ADMIN角色,其他的Actuator端点需要ACTUATOR角色。
3. 使用自定义的 Management Port
默认情况下,Actuator端点与应用程序的HTTP端口共享。为了增加安全性,你可以将Actuator端点配置在不同的端口上。这可以通过在application.properties或application.yml文件中设置management.server.port来实现。
例如,将Actuator端点配置在端口8081上:
management.server.port=8081
或者,使用YAML格式:
management:
server:
port: 8081
然后,你可以使用防火墙规则来限制对Actuator端口的访问,只允许特定的IP地址或网络访问。
注意:
- 如果
management.server.port设置为${server.port},则Actuator端点将与应用程序的HTTP端口共享。 - 如果
management.server.port设置为0,则Actuator端点将使用一个随机端口。
4. 使用IP地址白名单
如果你不需要公开Actuator端点,可以使用IP地址白名单来限制对Actuator端点的访问。这可以通过在application.properties或application.yml文件中设置management.endpoint.health.roles 和management.endpoint.info.roles 并结合Spring Security来实现。
首先,你需要启用 Spring Security,并配置一个用户和角色。
spring.security.user.name=actuator
spring.security.user.password=password
spring.security.user.roles=ACTUATOR
然后,配置Actuator端点,需要特定的角色才能访问
management.endpoint.health.roles=ACTUATOR
management.endpoint.info.roles=ACTUATOR
然后,配置 Spring Security 来允许特定的 IP 地址访问 Actuator 端点,可以通过实现一个自定义的 Filter 来实现:
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.springframework.stereotype.Component;
@Component
public class IPAddressFilter implements Filter {
private final List<String> allowedIPs = Arrays.asList("127.0.0.1", "0:0:0:0:0:0:0:1");
@Override
public void doFilter(
ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String clientIP = httpRequest.getRemoteAddr();
if (allowedIPs.contains(clientIP)) {
chain.doFilter(request, response);
} else {
httpResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
httpResponse.getWriter().write("Access Denied: Your IP is not allowed.");
}
}
}
最后,将这个 Filter 注册到 Spring Security 的 Filter Chain 中:
import org.springframework.beans.factory.annotation.Autowired;
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.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired private IPAddressFilter ipAddressFilter;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.authorizeHttpRequests(
authorize ->
authorize
.requestMatchers("/actuator/health", "/actuator/info")
.hasRole("ACTUATOR")
.anyRequest()
.permitAll())
.httpBasic();
http.addFilterBefore(ipAddressFilter, ChannelProcessingFilter.class);
return http.build();
}
}
5. 定制端点暴露
Spring Boot 2.x 引入了新的方式来控制端点的暴露,更加灵活,也更安全。我们可以使用 management.endpoints.web.exposure.include 和 management.endpoints.web.exposure.exclude 属性来控制哪些端点可以通过 Web 暴露。
management.endpoints.web.exposure.include: 指定要暴露的端点 ID 列表。 可以使用*暴露所有端点。management.endpoints.web.exposure.exclude: 指定要排除的端点 ID 列表。
例如,只暴露/health和/info端点:
management.endpoints.web.exposure.include=health,info
或者,使用YAML格式:
management:
endpoints:
web:
exposure:
include: health,info
这样,即使没有配置Spring Security,也只有/health和/info端点可以通过Web访问。
如果你想暴露所有端点,但是排除/env和/configprops端点:
management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=env,configprops
或者,使用YAML格式:
management:
endpoints:
web:
exposure:
include: '*'
exclude: env,configprops
6. 使用Jolokia进行远程管理
Jolokia是一个基于HTTP的JMX代理,允许你通过HTTP来访问和管理JMX MBean。如果你需要远程管理你的应用程序,可以使用Jolokia代替Actuator的/jolokia端点(已移除)。
首先,你需要添加Jolokia依赖到你的项目中:
Maven:
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>
Gradle:
implementation 'org.jolokia:jolokia-core'
然后,你需要配置Jolokia的访问控制。这可以通过在application.properties或application.yml文件中设置jolokia.config.policyLocation来实现。
例如,创建一个jolokia-access.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<restrictor>
<cors>
<origin>*</origin>
<methods>GET,HEAD,POST,OPTIONS</methods>
</cors>
<commands>
<command>read</command>
<command>write</command>
<command>list</command>
<command>search</command>
</commands>
<mbeans>
<mbean>
<name>java.lang:type=Memory</name>
<attributes>
<attribute>HeapMemoryUsage</attribute>
<attribute>NonHeapMemoryUsage</attribute>
</attributes>
</mbean>
</mbeans>
<clients>
<client address="127.0.0.1" host="localhost"/>
</clients>
</restrictor>
然后,在application.properties中配置jolokia.config.policyLocation:
jolokia.config.policyLocation=classpath:/jolokia-access.xml
或者,使用YAML格式:
jolokia:
config:
policyLocation: classpath:/jolokia-access.xml
注意:
- Jolokia的访问控制配置文件非常重要,请仔细配置。
- 建议只允许特定的IP地址或网络访问Jolokia。
7. 使用HTTPS
使用HTTPS加密所有Actuator端点的流量,可以防止中间人攻击。这可以通过配置Spring Boot的HTTPS支持来实现。
首先,你需要生成一个SSL证书。可以使用keytool命令生成一个自签名证书:
keytool -genkeypair -alias selfsigned -keyalg RSA -keystore keystore.jks -validity 3650
然后,你需要配置Spring Boot使用HTTPS。这可以通过在application.properties或application.yml文件中设置server.ssl.key-store、server.ssl.key-store-password和server.ssl.key-alias来实现。
例如:
server.ssl.key-store=keystore.jks
server.ssl.key-store-password=password
server.ssl.key-alias=selfsigned
server.ssl.enabled=true
或者,使用YAML格式:
server:
ssl:
key-store: keystore.jks
key-store-password: password
key-alias: selfsigned
enabled: true
注意:
- 在生产环境中,建议使用由受信任的证书颁发机构(CA)颁发的证书。
- 配置HTTPS后,所有Actuator端点都只能通过HTTPS访问。
8. 审计日志
启用Actuator的审计日志,可以记录所有对Actuator端点的访问,方便安全分析和问题排查。这可以通过配置management.auditevents.enabled=true来实现。
management.auditevents.enabled=true
或者,使用YAML格式:
management:
auditevents:
enabled: true
审计事件将记录在日志中,你可以使用日志分析工具来分析审计事件。
安全检查清单
在部署应用程序之前,请务必检查以下事项:
- [ ] 禁用不必要的Actuator端点。
- [ ] 使用Spring Security保护Actuator端点,并配置合适的角色和权限。
- [ ] 将Actuator端点配置在不同的端口上,并使用防火墙规则限制访问。
- [ ] 使用IP地址白名单限制对Actuator端点的访问。
- [ ] 定制端点暴露,只暴露必要的端点。
- [ ] 使用HTTPS加密所有Actuator端点的流量。
- [ ] 启用Actuator的审计日志。
- [ ] 定期审查Actuator的配置,确保安全策略得到有效执行。
Spring Boot Actuator 安全加固要点概括
安全加固Actuator端点至关重要,通过禁用不必要的端点、使用Spring Security进行认证授权、配置自定义端口和IP白名单、细粒度控制端点暴露、启用HTTPS和审计日志,能够有效防止敏感信息泄露和未经授权的访问,保障应用程序的安全。定期审查配置并保持警惕,是维护Actuator安全的关键。