我是靠谱客的博主 幸福宝贝,最近开发中收集的这篇文章主要介绍004. Eureka服务注册与欺骗你的EurekaServer,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

声明

不要使用此方法进行违法操作,本文只提供学习Eureka相关知识,涉及实验纯属个人娱乐。

前言

众所周知,在SpringCloud中使用的是json+http进行信息的交互,那么我们猜想,client端在启动时会将自己的信息以json方式发送给Server端,Server端接受后将信息存放到Cache中,那么等于注册了一个服务到Server端;再近一步,我们还可以一直发送/health的心跳检测,那么这个服务会一直存在于Eureka维护的核心容器中。这还不是最骚的,我们还可以直接强制下线某个微服务,然后自己"冒名顶替",这个黑户服务通过ip转发实现劫持。。。
所以你的微服务架构可千万不要"裸奔",安全第一位。

核心知识点

EurekaClient启动

EurekaClient客户端启动时会注入一些外部Bean:spring.factories文件

org.springframework.boot.autoconfigure.EnableAutoConfiguration=
org.springframework.cloud.netflix.eureka.config.EurekaClientConfigServerAutoConfiguration,
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceAutoConfiguration,
org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,
org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,
org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration,
org.springframework.cloud.netflix.eureka.reactive.EurekaReactiveDiscoveryClientConfiguration,
org.springframework.cloud.netflix.eureka.loadbalancer.LoadBalancerEurekaAutoConfiguration

org.springframework.cloud.bootstrap.BootstrapConfiguration=
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceBootstrapConfiguration

我们暂时关注EurekaClientAutoConfiguration,EurekaClientAutoConfiguration会注入一些Bean与Configuration,无论是热加载还是非热加载(@ConditionalOnRefreshScope与@ConditionalOnMissingRefreshScope先不多说)都会创建一个CloudEurekaClient对象。

// 例如:@ConditionalOnMissingRefreshScope
		@Bean(destroyMethod = "shutdown")
		@ConditionalOnMissingBean(value = EurekaClient.class,
				search = SearchStrategy.CURRENT)
		public EurekaClient eurekaClient(ApplicationInfoManager manager,
				EurekaClientConfig config) {
			return new CloudEurekaClient(manager, config, this.optionalArgs,
					this.context);
		}

这里面ApplicationInfoManager 包含了实例启动的config与当前实例的基本信息

		@Bean
		@ConditionalOnMissingBean(value = ApplicationInfoManager.class,
				search = SearchStrategy.CURRENT)
		@org.springframework.cloud.context.config.annotation.RefreshScope
		@Lazy
		public ApplicationInfoManager eurekaApplicationInfoManager(
				EurekaInstanceConfig config) {
			InstanceInfo instanceInfo = new InstanceInfoFactory().create(config);
			return new ApplicationInfoManager(config, instanceInfo);
		}

InstanceInfo包含了当前启动实例所有核心信息。
回到上面new的CloudEurekaClient,此对象在生成时提供方法反射获取HTTPclient:

    EurekaHttpClient getEurekaHttpClient() {
        if (this.eurekaHttpClient.get() == null) {
            try {
                Object eurekaTransport = this.eurekaTransportField.get(this);
                Field registrationClientField = ReflectionUtils.findField(eurekaTransport.getClass(), "registrationClient");
                ReflectionUtils.makeAccessible(registrationClientField);
                this.eurekaHttpClient.compareAndSet((Object)null, (EurekaHttpClient)registrationClientField.get(eurekaTransport));
            } catch (IllegalAccessException var3) {
                log.error("error getting EurekaHttpClient", var3);
            }
        }

        return (EurekaHttpClient)this.eurekaHttpClient.get();
    }

EurekaHttpClient功能强大(相当于注册发现的implement),他可以帮助Client进行注册,发现,取消,移除,状态修改,服务发现(全量,增量)等基础功能实现,在他的实现类中我们可以看到进行的http处理。

public interface EurekaHttpClient {
    EurekaHttpResponse<Void> register(InstanceInfo var1);

    EurekaHttpResponse<Void> cancel(String var1, String var2);

    EurekaHttpResponse<InstanceInfo> sendHeartBeat(String var1, String var2, InstanceInfo var3, InstanceStatus var4);

    EurekaHttpResponse<Void> statusUpdate(String var1, String var2, InstanceStatus var3, InstanceInfo var4);

    EurekaHttpResponse<Void> deleteStatusOverride(String var1, String var2, InstanceInfo var3);

    EurekaHttpResponse<Applications> getApplications(String... var1);

    EurekaHttpResponse<Applications> getDelta(String... var1);

    EurekaHttpResponse<Applications> getVip(String var1, String... var2);

    EurekaHttpResponse<Applications> getSecureVip(String var1, String... var2);

    EurekaHttpResponse<Application> getApplication(String var1);

    EurekaHttpResponse<InstanceInfo> getInstance(String var1, String var2);

    EurekaHttpResponse<InstanceInfo> getInstance(String var1);

    void shutdown();
}

EurekaDiscoveryClientConfiguration注入的Bean当然还包括服务注册的Bean(调用EurekaHttpClient.register的操作)

	@Bean
	public EurekaServiceRegistry eurekaServiceRegistry() {
		return new EurekaServiceRegistry();
	}
	
		@Bean
	@ConditionalOnBean(AutoServiceRegistrationProperties.class)
	@ConditionalOnProperty(
			value = "spring.cloud.service-registry.auto-registration.enabled",
			matchIfMissing = true)
	public EurekaAutoServiceRegistration eurekaAutoServiceRegistration(
			ApplicationContext context, EurekaServiceRegistry registry,
			EurekaRegistration registration) {
		return new EurekaAutoServiceRegistration(context, registry, registration);
	}

EurekaServiceRegistry包含的方法就是register,deregister,setStatus,getStatus。
DiscoveryClient会调用上面我们的httpclient

    boolean register() throws Throwable {
        logger.info("DiscoveryClient_{}: registering service...", this.appPathIdentifier);

        EurekaHttpResponse httpResponse;
        try {
            httpResponse = this.eurekaTransport.registrationClient.register(this.instanceInfo);
        } catch (Exception var3) {
            logger.warn("DiscoveryClient_{} - registration failed {}", new Object[]{this.appPathIdentifier, var3.getMessage(), var3});
            throw var3;
        }

        if (logger.isInfoEnabled()) {
            logger.info("DiscoveryClient_{} - registration status: {}", this.appPathIdentifier, httpResponse.getStatusCode());
        }

        return httpResponse.getStatusCode() == Status.NO_CONTENT.getStatusCode();
    }

开始实验

实验一,模拟注册一个微服务

为了方便EurekaHttpClient我们统一参照org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient的代码

    public EurekaHttpResponse<Void> register(InstanceInfo info) {
        String urlPath = this.serviceUrl + "apps/" + info.getAppName();
        HttpHeaders headers = new HttpHeaders();
        headers.add("Accept-Encoding", "gzip");
        headers.add("Content-Type", "application/json");
        ResponseEntity<Void> response = this.restTemplate.exchange(urlPath, HttpMethod.POST, new HttpEntity(info, headers), Void.class, new Object[0]);
        return EurekaHttpResponse.anEurekaHttpResponse(response.getStatusCodeValue()).headers(headersOf(response)).build();
    }

我们使用的url为http://localhost:7001/eureka/apps/PROVIDER-PAYMENT8002;
通过抓包获取到报文结构:
EurekaClient注册报文
我们使用此报文

{
    "instance": {
        "instanceId": "provider-payment8002",
        "hostName": "192.168.0.106",
        "app": "PROVIDER-PAYMENT8002",
        "ipAddr": "192.168.0.106",
        "status": "UP",
        "overriddenStatus": "UNKNOWN",
        "port": {
            "$": 8002,
            "@enabled": "true"
        },
        "securePort": {
            "$": 443,
            "@enabled": "false"
        },
。。。
        "homePageUrl": "http://192.168.0.106:8002/",
        "statusPageUrl": "http://192.168.0.106:8002/actuator/info",
        "healthCheckUrl": "http://192.168.0.106:8002/actuator/health",
        "vipAddress": "provider-payment8002",
        "secureVipAddress": "provider-payment8002",
        "isCoordinatingDiscoveryServer": "false",
        "lastUpdatedTimestamp": "1584033235520",
        "lastDirtyTimestamp": "1584033236309"
    }
}

post请求
已经注册成功

实验二,下线一个微服务

    public EurekaHttpResponse<Void> cancel(String appName, String id) {
        String urlPath = this.serviceUrl + "apps/" + appName + '/' + id;
        ResponseEntity<Void> response = this.restTemplate.exchange(urlPath, HttpMethod.DELETE, (HttpEntity)null, Void.class, new Object[0]);
        return EurekaHttpResponse.anEurekaHttpResponse(response.getStatusCodeValue()).headers(headersOf(response)).build();
    }

这里的id是什么呢?DiscoveryClient中有,即instanceInfo.getId(),默认是微服务的小写:

    void unregister() {
        if (this.eurekaTransport != null && this.eurekaTransport.registrationClient != null) {
            try {
                logger.info("Unregistering ...");
                EurekaHttpResponse<Void> httpResponse = this.eurekaTransport.registrationClient.cancel(this.instanceInfo.getAppName(), this.instanceInfo.getId());
                logger.info("DiscoveryClient_{} - deregister  status: {}", this.appPathIdentifier, httpResponse.getStatusCode());
            } catch (Exception var2) {
                logger.error("DiscoveryClient_{} - de-registration failed{}", new Object[]{this.appPathIdentifier, var2.getMessage(), var2});
            }
        }

    }

所以我们的url是:http://localhost:7001/eureka/apps/PROVIDER-PAYMENT8002/provider-payment8002
delete请求。
服务下线

实验三,服务劫持

将生产的8001下线操作http://localhost:7001/eureka/apps/PROVIDER-PAYMENT8001/provider-payment8001,然后启动一个脚本定时任务,先发送请求将自己注册上Eureka,并且每30s发送健康检查,发送请求,请求可以被此第三方服务正常消费,即实验成功。
脚本服务

最后

以上就是幸福宝贝为你收集整理的004. Eureka服务注册与欺骗你的EurekaServer的全部内容,希望文章能够帮你解决004. Eureka服务注册与欺骗你的EurekaServer所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(41)

评论列表共有 0 条评论

立即
投稿
返回
顶部