Spring Cloud Gateway中对admin端点进行认证

前言

我们被扫了一个漏洞,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

xml 复制代码
 <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/**进行认证,其他地址放行,使用业务自身认证。

java 复制代码
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,配置为

java 复制代码
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认证使用自定义的处理逻辑
    @Autowired
    private 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);

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(inMemoryUserDetailsManager);
    }

    @Bean
    public 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;
    }

    @Override
    protected 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 系列文章

  1. Prometheus 的介绍和安装
  2. 直观感受PromQL及其数据类型
  3. PromQL之选择器和运算符
  4. PromQL之函数
  5. Prometheus 告警机制介绍及命令解读
  6. Prometheus 告警模块配置深度解析
  7. Prometheus 配置身份认证
  8. Prometheus 动态拉取监控服务
  9. Prometheus 监控云Mysql和自建Mysql

Grafana 系列文章,版本:OOS v9.3.1

  1. Grafana 的介绍和安装
  2. Grafana监控大屏配置参数介绍(一)
  3. Grafana监控大屏配置参数介绍(二)
  4. Grafana监控大屏可视化图表
  5. Grafana 查询数据和转换数据
  6. Grafana 告警模块介绍
  7. Grafana 告警接入飞书通知

相关推荐
回家路上绕了弯2 小时前
内容平台核心工程:最热帖子排行实现与用户互动三元组存储查询
后端·微服务
qqxhb2 小时前
系统架构设计师备考第63天——通信系统架构
5g·系统架构·局域网·通信系统·sdn·广域网·存储网络san/nas
_Walli_2 小时前
k8s集群搭建(七)-------- 微服务间的调用
微服务·容器·kubernetes
装不满的克莱因瓶2 小时前
【Java架构师】各个微服务之间有哪些调用方式?
java·开发语言·微服务·架构·dubbo·restful·springcloud
陈果然DeepVersion5 小时前
Java大厂面试真题:Spring Boot+Kafka+AI智能客服场景全流程解析(十一)
java·spring boot·微服务·ai·kafka·面试题·rag
qqxhb6 小时前
系统架构设计师备考第67天——数据库系统的安全&系统架构的脆弱性
数据库·安全·系统架构·访问控制·完整性·脆弱性·身份鉴别
小鱼儿LY6 小时前
系统架构设计师论文-论软件体系结构的演化
系统架构·软件体系结构·架构设计师·体系结构演化
pan30350747918 小时前
GRPC详解
微服务·grpc
qqxhb19 小时前
系统架构设计师备考第64天——网络构建关键技术
网络·系统架构·mtbf·mttr·冗余硬件·软件热备·快速检测
喵个咪19 小时前
开箱即用的GO后台管理系统 Kratos Admin - 站内信
后端·微服务·go