前言
我們被掃了一個漏洞,SpringBoot Actuator 未授權訪問
,漏洞描述是這樣的:
Actuator 是 springboot 提供的用來對應用系統進行自省和監控的功能模塊,借助于 Actuator 開發者可以很方便地對應用系統某些監控指標進行查看、統計等。在 Actuator 啟用的情況下,如果沒有做好相關權限控制,非法用戶可通過訪問默認的執行器端點(endpoints)來獲取應用系統中的監控信息,從而導致信息泄露甚至服務器被接管的事件發生
正文
如果沒有對admin的端點進行鑒權,那么對于開放的網關服務,可以直接通過xx/actuator
訪問,這將是非常危險的,如果你還暴露了所有端點,那么還可以獲取環境中的賬號密碼信息,即使admin做了脫敏。
要對端點進行鑒權,也非常簡單,只需要要引入spring-security
依賴即可,下面是Spring Cloud Gateway中的配置。
1、引入xml依賴
spring-boot-starter-web
scope 是provided,引入gateway中不能有web
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><scope>provided</scope></dependency>
2、針對Admin端點認證的配置,只對/actuator/**
進行認證,其他地址放行,使用業務自身認證。
package com.frame.ops.admin.client.config;import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;/*** 對客戶端的actuator接口進行鑒權* 引入后,gateway 有性能問題*/
@EnableWebFluxSecurity
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class ReactiveAdminSecurityConfig {@Bean@Order(1)public SecurityWebFilterChain authorizationServerSecurityFilterChain(ServerHttpSecurity http) {http.authorizeExchange()//只對actuator接口認證.pathMatchers("/actuator/**").authenticated().anyExchange().permitAll().and().httpBasic().and().csrf().disable();return http.build();}}
3、如果是Servlet,配置為
package com.frame.ops.admin.client.config;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.util.StringUtils;import java.util.List;
import java.util.regex.Pattern;/*** 對客戶端的actuator接口進行鑒權*/
@Order(1)
@EnableWebSecurity
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class AdminSecurityConfig extends WebSecurityConfigurerAdapter {//這個InMemoryUserDetailsManager,如果你的業務中也使用了spring security,那么需要自定義一 //個,防止admin認證使用自定義的處理邏輯@Autowiredprivate InMemoryUserDetailsManager inMemoryUserDetailsManager;private static final String NOOP_PASSWORD_PREFIX = "{noop}";private static final Pattern PASSWORD_ALGORITHM_PATTERN = Pattern.compile("^\\{.+}.*$");private static final Log logger = LogFactory.getLog(AdminSecurityConfig.class);@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(inMemoryUserDetailsManager);}@Beanpublic InMemoryUserDetailsManager inMemoryUserDetailsManager(SecurityProperties properties,ObjectProvider<PasswordEncoder> passwordEncoder) {SecurityProperties.User user = properties.getUser();List<String> roles = user.getRoles();return new InMemoryUserDetailsManager(User.withUsername(user.getName()).password(getOrDeducePassword(user, passwordEncoder.getIfAvailable())).roles(StringUtils.toStringArray(roles)).build());}private String getOrDeducePassword(SecurityProperties.User user, PasswordEncoder encoder) {String password = user.getPassword();if (user.isPasswordGenerated()) {logger.warn(String.format("%n%nUsing generated security password: %s%n%nThis generated password is for development use only. "+ "Your security configuration must be updated before running your application in "+ "production.%n",user.getPassword()));}if (encoder != null || PASSWORD_ALGORITHM_PATTERN.matcher(password).matches()) {return password;}return NOOP_PASSWORD_PREFIX + password;}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests()//只有actuator開頭的請求才需要認證.antMatchers("/actuator/**").authenticated().anyRequest().permitAll().and().httpBasic();}}
總結
?? 奇怪的事來了,在本地測試gateway 請求正常,訪問
/actuator
端點需要認證,但是在服務器上測試一些業務接口就會卡住超時,請求也沒到下游服務,過段時間后gateway 假死,任何請求不通。
這個問題只發生在gateway中,對應servlet并沒有發現這個問題,不清楚跟Gateway 使用Reactive 有沒有關系, 這個問題暫未解決。但也不影響處理漏洞,只要去掉admin依賴,actuator依賴就行了。
作者其他要推薦的文章,歡迎來學習:
Prometheus 系列文章
- Prometheus 的介紹和安裝
- 直觀感受PromQL及其數據類型
- PromQL之選擇器和運算符
- PromQL之函數
- Prometheus 告警機制介紹及命令解讀
- Prometheus 告警模塊配置深度解析
- Prometheus 配置身份認證
- Prometheus 動態拉取監控服務
- Prometheus 監控云Mysql和自建Mysql
Grafana 系列文章,版本:OOS v9.3.1
- Grafana 的介紹和安裝
- Grafana監控大屏配置參數介紹(一)
- Grafana監控大屏配置參數介紹(二)
- Grafana監控大屏可視化圖表
- Grafana 查詢數據和轉換數據
- Grafana 告警模塊介紹
- Grafana 告警接入飛書通知