Java配置47-Spring Eureka 未授权访问漏洞修复
作者:mmseoamin日期:2023-12-05

文章目录

    • 1. 背景
    • 2. 方法
      • 2.1 Eureka Server 添加安全组件
      • 2.2 Eureka Server 添加参数
      • 2.3 重启 Eureka Server
      • 2.4 Eureka Server 升级版本
      • 2.5 Eureka Client 配置
      • 2.6 Eureka Server 添加代码
      • 2.7 其他问题

        1. 背景

        项目组使用的 Spring Boot 比较老,是 1.5.4.RELEASE 。最近被检测出 Spring Eureka 未授权访问漏洞。

        现状是浏览器直接访问 Eureka Server 可以直接进去,看到已经注册的服务信息。

        在这里插入图片描述

        2. 方法

        2.1 Eureka Server 添加安全组件

        Eureka Server 添加 pom 依赖:

                
                    org.springframework.boot
                    spring-boot-starter-security
                
        

        2.2 Eureka Server 添加参数

        spring.application.name:demo-eureka
        server.port: 8088
        eureka.instance.hostname=localhost
        #禁用将自己作为客户端注册,禁用客户端注册行为
        eureka.client.register-with-eureka=false
        eureka.client.fetch-registry=false
        #eureka地址
        eureka.client.service-url.defaultZone=http://${spring.security.user.name}:${spring.security.user.password}@${eureka.instance.hostname}:${server.port}/eureka
        #eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka
        #关闭自我保护 --本地开发环境可以关闭,生产环境
        eureka.server.enable-self-preservation = false
        #清理节点时间
        eureka.server.eviction-interval-timer-in-ms = 60000
        spring.security.basic.enabled=true
        spring.security.user.name=demo
        spring.security.user.password=123abcd
        

        2.3 重启 Eureka Server

        重启 Eureka Server ,然后刷新访问页面,显示登录框:

        在这里插入图片描述

        输入配置的用户名和密码。

        spring.security.user.name=demo
        spring.security.user.password=123abcd
        

        然后就报错了:Reason: Bad credentials。

        在这里插入图片描述

        奇怪,明明是按照配置文件里面输入的,怎么还会报用户名或密码错误呢。

        查了一些资料,说跟 security 加密方法有关,整了半天搞不定。

        2.4 Eureka Server 升级版本

        实在没招了,只能怀疑用的框架版本太低,去重新整一个,eureka 就用了个服务发现,问题不大。

        访问:https://start.spring.io/

        在这里插入图片描述

        把项目下载到本地,依赖已经加好了:

        	
        		
        			org.springframework.boot
        			spring-boot-starter-security
        		
        		
        			org.springframework.cloud
        			spring-cloud-starter-netflix-eureka-server
        		
        		
        			org.springframework.boot
        			spring-boot-starter-test
        			test
        		
        		
        			org.springframework.security
        			spring-security-test
        			test
        		
        	
        	
        		
        			
        				org.springframework.cloud
        				spring-cloud-dependencies
        				${spring-cloud.version}
        				pom
        				import
        			
        		
        

        在启动类上加上注解:

        package com.demo.cloudeurekaserver;
        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
        @EnableEurekaServer
        @SpringBootApplication
        public class CloudEurekaServerApplication {
        	public static void main(String[] args) {
        		SpringApplication.run(CloudEurekaServerApplication.class, args);
        	}
        }
        

        再把 2.2 的参数加到 properties 文件中(最好换个 server.port),然后 run 启动类,访问 eureka ,输入用户名和密码,进去了:

        在这里插入图片描述

        2.5 Eureka Client 配置

        eureka client 参数:

        eureka.client.enabled=true
        eureka.client.eureka-server-port=8089
        eureka.client.service-url.defaultZone=http://demo:123abcd@localhost:8089/eureka/
        

        启动 eureka client,报错:

        javax.ws.rs.WebApplicationException: null
        	at com.netflix.discovery.provider.DiscoveryJerseyProvider.readFrom(DiscoveryJerseyProvider.java:110)
        	at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:634)
        	at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:586)
        	at com.netflix.discovery.shared.transport.jersey.AbstractJerseyEurekaHttpClient.sendHeartBeat(AbstractJerseyEurekaHttpClient.java:105)
        	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$3.execute(EurekaHttpClientDecorator.java:92)
        	at com.netflix.discovery.shared.transport.decorator.MetricsCollectingEurekaHttpClient.execute(MetricsCollectingEurekaHttpClient.java:73)
        	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.sendHeartBeat(EurekaHttpClientDecorator.java:89)
        	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$3.execute(EurekaHttpClientDecorator.java:92)
        	at com.netflix.discovery.shared.transport.decorator.RedirectingEurekaHttpClient.executeOnNewServer(RedirectingEurekaHttpClient.java:118)
        	at com.netflix.discovery.shared.transport.decorator.RedirectingEurekaHttpClient.execute(RedirectingEurekaHttpClient.java:79)
        	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.sendHeartBeat(EurekaHttpClientDecorator.java:89)
        	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$3.execute(EurekaHttpClientDecorator.java:92)
        	at com.netflix.discovery.shared.transport.decorator.RetryableEurekaHttpClient.execute(RetryableEurekaHttpClient.java:119)
        	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.sendHeartBeat(EurekaHttpClientDecorator.java:89)
        	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$3.execute(EurekaHttpClientDecorator.java:92)
        	at com.netflix.discovery.shared.transport.decorator.SessionedEurekaHttpClient.execute(SessionedEurekaHttpClient.java:77)
        	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.sendHeartBeat(EurekaHttpClientDecorator.java:89)
        	at com.netflix.discovery.DiscoveryClient.renew(DiscoveryClient.java:824)
        	at com.netflix.discovery.DiscoveryClient$HeartbeatThread.run(DiscoveryClient.java:1388)
        	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        	at java.lang.Thread.run(Thread.java:748)
        2023-11-03 14:41:26.339  WARN [test-app-service,,,] 16240 --- [tbeatExecutor-0] c.n.d.s.t.d.RetryableEurekaHttpClient    : Request execution failed with message: null
        2023-11-03 14:41:26.339 ERROR [test-app-service,,,] 16240 --- [tbeatExecutor-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_TEST-APP-SERVICE/10.136.44.122:test-app-service:60000 - was unable to send heartbeat!
        com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server
        	at com.netflix.discovery.shared.transport.decorator.RetryableEurekaHttpClient.execute(RetryableEurekaHttpClient.java:111)
        	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.sendHeartBeat(EurekaHttpClientDecorator.java:89)
        	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$3.execute(EurekaHttpClientDecorator.java:92)
        	at com.netflix.discovery.shared.transport.decorator.SessionedEurekaHttpClient.execute(SessionedEurekaHttpClient.java:77)
        	at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.sendHeartBeat(EurekaHttpClientDecorator.java:89)
        	at com.netflix.discovery.DiscoveryClient.renew(DiscoveryClient.java:824)
        	at com.netflix.discovery.DiscoveryClient$HeartbeatThread.run(DiscoveryClient.java:1388)
        	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        	at java.lang.Thread.run(Thread.java:748)
        

        刷新 eureka 页面,也没有服务信息,服务注册失败了。

        这是因为从 Spring Boot 2.0 开始,默认情况下会启用CSRF保护,以防止CSRF攻击应用程序,导致服务注册失败。

        2.6 Eureka Server 添加代码

        修改 Eureka Server :

        package com.demo.cloudeurekaserver;
        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
        import org.springframework.security.config.annotation.web.builders.HttpSecurity;
        import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
        import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
        @EnableEurekaServer
        @SpringBootApplication
        public class CloudEurekaServerApplication {
        	public static void main(String[] args) {
        		SpringApplication.run(CloudEurekaServerApplication.class, args);
        	}
        	/**
        	 * springboot 从 2.0 开始,默认情况下会启用CSRF保护
        	 * 需要关闭
        	 */
        	@EnableWebSecurity
        	static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        		@Override
        		protected void configure(HttpSecurity http) throws Exception {
        			//方法1:关闭csrf
        //			http.csrf().disable();
        			//方法2:忽略/eureka/** 所有请求
        			http.csrf().ignoringAntMatchers("/eureka/**");
        			super.configure(http);
        		}
        	}
        }
        

        重启 Eureka Server 和 Eureka Client ,这次没有报错,刷新页面,重新登录后,看到注册的服务信息:

        在这里插入图片描述

        2.7 其他问题

        在 Spring Security 5.7.0-M2 中,WebSecurityConfigurerAdapter 被弃用了,Spring 鼓励用户转向基于组件的安全配置。这意味着,现在应该使用基于组件的安全配置来配置 HttpSecurity,而不是继承 WebSecurityConfigurerAdapter。这种方式更加灵活,可以更好地支持 Spring Boot 2.x 和 Spring 5.x。

        在这里插入图片描述

        我试了几个方法,没有替换掉,靠你了,耿小姐。

        先这样吧。

        在这里插入图片描述

        (图网,侵删)