专栏首页我要变牛又双叒被eureka坑了

又双叒被eureka坑了

Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。

Eureka包含两个组件:Eureka Server和Eureka Client。具体怎么部署这里就不说了,直接说问题

Eureka 客户端注册时需要配置服务端地址,类似如下配置

eureka:
  instance:
    hostname: hello-service
    prefer-ip-address: true
    instance-id: ${eureka.instance.hostname}:${server.port}
  client:
    register-with-eureka: true 
    fetch-registry: true
    service-url: 
     defaultZone: "http://localhost:8761/eureka/" 

这种配置后客户端就会注册到Eureka注册中心,在Eureka界面就能看到:

但是这样把界面暴露到外面,会把注册信息泄漏,一般公司也不允许暴露没有安全认证的后台界面

所以尝试把Eureka界面加密

引入security

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Eureka服务端增加basic鉴权:

spring:
  application:
    name: eureka-server 
  security: 
    basic:
      enabled: true
    user:
      name: admin
      password: 123456

配置完成后发现现在访问eureka界面需要用户名和密码登录了

但是登录进去后发现刚才的hello服务并没有注册进来

呕吼,应该是客户端没配置鉴权信息的原因,在官网找到了客户端鉴权配置方式

https://cloud.spring.io/spring-cloud-netflix/multi/multi__service_discovery_eureka_clients.html

于是在hello服务修改配置如下:

eureka:
  instance:
    hostname: hello-service
    prefer-ip-address: true
    instance-id: ${eureka.instance.hostname}:${server.port}
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://admin:123456@localhost:8761/eureka/

重启hello服务后,发现还是没有注册成功,原来增加basic验证后,不支持跨域访问了,我的天,你这个大坑,服务注册肯定是跨域的了,

于是,迅速增加配置,去掉跨域拦截

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
     // http.csrf().disable();//一种方式直接关闭csrf,另一种配置url后放行
        http.csrf().ignoringAntMatchers("/eureka/**");
        super.configure(http);
    }
}

终于在界面看到可可爱爱的hello服务了,但是呢,还有一个问题,现在不允许这种明文密码出现在配置或代码中,怎么办呢?

首先想到的就是密码加密, 所以从spring-securiry中找到PasswordEncoderFactories加密

PasswordEncoderFactories.createDelegatingPasswordEncoder().encode("123456")

然后把加密后的结果放到Eureka服务端配置文件中:

security: 
  basic:
    enabled: true 
  user:
    name: admin
    password: '{bcrypt}$2a$10$mhH7ogkRB91YDUO3F883JugDMHz2o6miT95.8ukqEc6Ed4Z2xyHmm' //必须有引号

那Eureka客户端怎么办?同样道理的嘛

client:
  register-with-eureka: true
  fetch-registry: true
  service-url:
    defaultZone: http://admin:{bcrypt}$2a$10$mhH7ogkRB91YDUO3F883JugDMHz2o6miT95.8ukqEc6Ed4Z2xyHmm@localhost:8761/eureka/

但是呢,启动直接报错,害,eureka注册时并不会解密

解析Eureka服务端地址失败,即使是加上引号也是报相同错误

Eureka客户端注册过来的消息,服务端并不会给解密,那怎么办呢?

从上图可以看到如果要实现更复杂的需求,需要通过注入clientFilter方式,so,搞起来

@Configuration
@Priority(Integer.MIN_VALUE)
public class UserCilentFilter extends ClientFilter {
    @Override
    public ClientResponse handle(ClientRequest clientRequest) throws ClientHandlerException {
        try {
            String originUrl = clientRequest.getURI().toString();
            if(originUrl.contains("@")){
                return this.getNext().handle(clientRequest);
            }
            String userNameAndPwd = "http://admin"+ jiemi("'{bcrypt}$2a$10$mhH7ogkRB91YDUO3F883JugDMHz2o6miT95.8ukqEc6Ed4Z2xyHmm'");
            String addUserInfoUrl = originUrl.replaceFirst("http://", userNameAndPwd);
            clientRequest.setURI(new URI(addUserInfoUrl));
        } catch (URISyntaxException e) {
            // FIXME: 2021/4/2
        }
        return this.getNext().handle(clientRequest);
    }

    private String jiemi(String pwd) {
        // FIXME: 解密
        return pwd;
    }


    @Bean
    public DiscoveryClient.DiscoveryClientOptionalArgs discoveryClientOptionalArgs() {
        DiscoveryClient.DiscoveryClientOptionalArgs discoveryClientOptionalArgs = new DiscoveryClient.DiscoveryClientOptionalArgs();
        discoveryClientOptionalArgs.setAdditionalFilters(Collections.singletonList(new UserCilentFilter()));
        return discoveryClientOptionalArgs;
    }
}

这样写的思路是让其他客户端注册时去掉用户名和密码,然后在自定义过滤器中对没有用户名和密码时补充上basic验证的用户名和密码

然后开始测试,这样还是不行,其他服务注册过来时,会被其他安全过滤器拦截都走不到自定义的拦截器就返回鉴权失败了,即使@Priority(Integer.MIN_VALUE)最高优先级

那是不是可以在更前面的地方进行拦截呢?增加ServletRequest拦截器可行否?

@Configuration
public class ServerRequestAuthFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain filterChain) throws IOException, ServletException {
        //业务实现,根据请求的IP或者参数判断是否可以执行注册或者访问
//        String addUserInfoUrl = originUrl.replaceFirst("http://", "http://admin:123456@");
        filterChain.doFilter(request, response);
    }
}

但是假设这样修改后,登录的web界面也会走到这个拦截器,同样会增加鉴权

也就是说这样直接增加鉴权,无法区分是其他客户端注册还是从界面访问

也没有什么太好的办法了,就直接在security的拦截器中把eureka注册相关的放掉,不进行鉴权操作

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().antMatchers("/eureka/**").permitAll();
    super.configure(http);
}

这样设置后除了直接访问的界面需要鉴权外,其他eureka相关注册、查询等不需要鉴权

都这样分层鉴权操作了,再找下是不是有其他方式达到相同的目的,于是找到

eureka:
  dashboard:
    enabled: false

通过在启动脚本设置后,效果是类似的,在eureka主界面无法访问

上面所有的操作都是为了信息安全考虑,还有一个经常忘记需要考虑的组件是Spring Boot Actuator,针对 Spring Boot Actuator 提供的 endpoint,采取以下几种措施,可以尽可能降低被安全攻击的风险

  1. 最小粒度暴露 endpoint。只开启并暴露真正用到的 endpoint,而不是配置:management.endpoints.web.exposure.include=*。
  2. 为 endpoint 配置独立的访问端口,从而和 web 服务的端口分离开,避免暴露 web 服务时,误将 actuator 的 endpoint 也暴露出去。例:management.port=8099。
  3. 引入 spring-boot-starter-security 依赖,为 actuator 的 endpoint 配置访问控制。
  4. 慎重评估是否需要引入 spring-boot-stater-actuator。以我个人的经验,我至今还没有遇到什么需求是一定需要引入spring-boot-stater-actuator 才能解决,如果你并不了解上文所述的安全风险,我建议你先去除掉该依赖。

信息安全已经成为各大公司不得不考虑的问题,所以精准的权限控制也是必不可少的,希望本文对大家在使用SpringCloud相关组件安全控制上有启发作用。

如果觉得俺写的还可以,记得点赞,一键三连也不介意。

☞☞每周一篇,赛过神仙,看完点赞,养成习惯☜☜

本文分享自微信公众号 - 你呀不牛(notNiu),作者:不牛

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-04-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 又双叒有域名被安排了。。。

    “ 我们周遭的一切事物都始于设计。.design域名专为设计行业服务,是互联网中的精准门牌号,也是除了.com域名以外的另一个绝佳选择。设计不仅仅是个特定的...

    腾讯云DNSPod团队
  • 我又双叒叕崩了!!!

    对于程序员来说,都希望代码可以实现一步到位,绕开令人头疼的BUG。但是在程序员的编程生涯中,免不了和BUG打交道。

    老九君
  • 磁盘又双叒叕满了~

    关于石头哥:新时代农民工,末流985逆袭保送清华,BAT 大厂码农,欢迎关注程序猿石头(ID: tangleithu),这里经常能get意想不到的知识点

    程序猿石头
  • QIIME2又双叒叕更新了

    提醒一下,我们计划发布的 QIIME 2 计划于 2020 年 8 月发布 (QIIME 2 2020.8),但请继续关注更新。

    用户1075469
  • 摩拜服务器又双叒叕挂了

    今天摩拜推送红包活动之后,傍晚时分,服务器又挂了,这次应该和9月份服务器宕机不一样,在9月份宕机的时候技术储备不足,这么长时间摩拜单车都没有把服务器问题解决,看...

    Leoo Bai
  • RocketMQ又双叒叕system busy了,怎么破?

    最近收到很多RocketMQ使用者反馈在消息发送过程中偶尔会出现如下4个错误信息之一:

    Bug开发工程师
  • H5上传文件又双叒叕开测了!

    1.H5上传的素材页面只显示通过H5上传的素材,PC上传的素材不同步至H5,H5上传的素材实时同步至PC对应的素材Tab页;

    ITester软件测试小栈
  • 腾讯云音视频被腾讯财报cue了:又双叒第一名!

    ? 2021年8月18日,腾讯公布2021年第二季度业绩报告: 凭藉云基础设施、PaaS及SaaS技术,我们助力公共服务及传统行业实现数字化。我们在技术及产品...

    腾讯云音视频
  • 你的飞机为什么又双叒叕延误了?

    延误,是每一位空中飞人的切肤之痛。2016年,国内航班总量虽然增长15.5%,但平均延误时长却增长了一半,准点的航班不足7成。飞常准的CMO秦天遣称正在尝试用...

    DT数据侠
  • 腾讯云商标注册又双叒叕bug价了?

    知识产权保护,微信在行动 今年4月26日,是第20个世界知识产权日。当天,微信发布了《2019年微信知识产权保护数据全景图》,这是一份微信在2019年一整年,...

    腾讯云DNSPod团队
  • 洞察 | 用几份数据告诉你《王者荣耀》毒性在哪?

    《王者荣耀》系统又双叒更新了,新赛季的系统以夏侯淳、小乔和钟无艳的夏日皮肤为主题封面,钟无艳也从一个肌肉姐姐变成了大长腿美女。夏日主题虽然养眼活泼,背景音乐等...

    灯塔大数据
  • 谷歌最新验证系统又双叒被「破解」了,这次是强化学习

    对于谷歌浏览器的用户来说,上面这幅画面想必并不陌生。这是谷歌开发的验证码系统 reCaptcha,旨在确认访问者是人还是程序,并防止恶意程序的入侵。

    机器之心
  • 做题总结——王母娘娘又双叒叕来难为茶山牛了

    我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite...

    用户8224910
  • 一周AI资讯|智能界又双叒出新花样了!

    今日,百度正式发布首款自有品牌智能音箱“小度智能音箱”,其拥有ARM cortex 4核处理器、高灵敏度全频喇叭等不妥协的硬件搭配,专业级公放和调音。小度智能包...

    用户1386409
  • 我服务又双叒叕奔溃了,含泪干货分享

    一开始以为是服务本身导致的问题,但是最近一个礼拜都没有提交记录,所以应该不是因为异常提交导致的,只能先重启服务,看看能不能恢复过来。但是重启服务之后还是报类似的...

    林老师带你学编程
  • Spring Cloud Eureka Client的使用

    第一篇了解了Spring Cloud Eureka Server 之后,我们就可以搭建起单机或者简单集群的注册中心,此时已经可以允许客户端将服务注册到eurek...

    不蜇人的小蜜蜂
  • ntp网络时间服务器又双叒叕出新功能了

    ntp网络时间服务器是依靠GPS时钟服务器通过GPS天线从 GPS地球同步卫星上获取标准时钟信号信息,然后在NTP协议的基础上,网络授时系统将这些时钟信息在网络...

    时频专家
  • 又双叒叕更新了!这些功能你一定用得上

    交作业!腾讯待办又双叒叕更新了,重复任务提醒更加智能,轻松避开法定节假日的打扰;同时,提醒方式也越加丰富,多重提醒让你告别遗忘的烦恼。话不多说,下面一起来看看吧...

    腾讯待办
  • 又双叒叕有活动了?四舍五入等于不要钱!!

    ? ? ? ? DNSPod域名限时特惠又来啦!大家一起来看看是哪些后缀吧~ ? ? ? .xyz限时组合特惠 云服务器1核2G+.xyz域名  31元/组合...

    腾讯云DNSPod团队

扫码关注云+社区

领取腾讯云代金券