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相关组件安全控制上有启发作用。

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

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

小心,别被eureka坑了的更多相关文章

  1. 最近C#项目中不小心踩的低级坑

    都是很基础的错误问题,大部分都是因为不查一下资料就直接根据其它类似语言的经验写代码导致的 1. 一个企业微信上的正常的界面突然不能滚动了 本以为是浏览器代码计算问题,结果发现是JS出错导致. 2. R ...

  2. 记录一个微信网页授权中不小心踩到的坑(Curl请求返回false)

    原文章地址在这里 这个问题是file_get_contents不能获取https的内容引起的.这样的情况下,我们一般会采用curl拓展来模拟请求. 代码demo(当然这是错误的示范): functio ...

  3. 小心!FOMO3D的坑

    null 01 前方高能 近日,区块链机构安比(SECBIT)实验室审计后确认,FOMO3D游戏的智能合约存在随机数漏洞可被利用,FOMO3D合约及所有抄袭源码的山寨合约均存在该安全漏洞. 原本设计上 ...

  4. python中的这些坑,早看早避免。

    python中的这些坑,早看早避免. 说一说python中遇到的坑,躲坑看这一篇就够了 传递参数时候不要使用列表 def foo(num,age=[]): age.append(num) print( ...

  5. alibaba之Nacos

    本文为转载文章 原文链接:https://windmt.com/2018/11/09/intro-to-spring-cloud-alibaba-nacos/ 上个月最后一天的凌晨,Spring Cl ...

  6. [转] 传统 Ajax 已死,Fetch 永生

    原谅我做一次标题党,Ajax 不会死,传统 Ajax 指的是 XMLHttpRequest(XHR),未来现在已被 Fetch 替代. 最近把阿里一个千万级 PV 的数据产品全部由 jQuery 的  ...

  7. 关于mybatis用mysql时,插入返回自增主键的问题

    公司决定新项目用mybatis,虽然这个以前学过但是一直没用过都忘得差不多了,而且项目比较紧,也没时间去系统点的学一学,只好很粗略的百度达到能用的程度就行了. 其中涉及到插入实体要求返回主键id的问题 ...

  8. 面试前的准备---C#知识点回顾----03

    经过一天的奔波,喜忧参半,不细表 再回看下标题,C#知识点回顾 再看下内容,数据库3NF 原谅我这个标题党 今天继续回忆 1.HTTP中Post和Get区别 这忒简单了吧,大家是不是感觉到兴奋了,长舒 ...

  9. 传统 Ajax 已死,Fetch 永生

    原谅我做一次标题党,Ajax 不会死,传统 Ajax 指的是 XMLHttpRequest(XHR),未来现在已被 Fetch 替代. 最近把阿里一个千万级 PV 的数据产品全部由 jQuery 的  ...

随机推荐

  1. 可视化埋点 & XPath

    可视化埋点 & XPath https://www.w3.org/TR/xpath-full-text-30/ 数据的准确性 采集时机 数据发送策略 full XPath demo XML & ...

  2. DENIEL SOIBIM:如何保持坚持

    丹尼尔·索比姆作为加州理工高材生,在2005年通过创建投资俱乐部对潜力公司进行天使投资,获得了美国Blue Run高层的重视,并相继担任Blue Run潜力营收专家评估师,2009年成为星盟集团的副总 ...

  3. short i=1;i=i+1;为什么报错?

    先测试,看结果: 提示我们说不能将short类型的转化为int类型! 先不急着下结论,我们继续测试,用i+=1; 我们发现并没有报错,为什么同样是加1,会出现这样两种不同的结果呢? 查阅了一些资料,大 ...

  4. 框架进行时——SSM整合基础环境搭建

    一.导入相关的依赖 1 <!--打war包--> 2 <packaging>war</packaging> 3 4 <!--版本锁定--> 5 < ...

  5. vue-axios插件、django-cors插件、及vue如何使用第三方前端样式库:element/jQuery/bootstrap

    目录 一.vue的ajax插件:axios 1.安装axios 2.axios参数 二.CORS跨域问题(同源策略) 1.Django解决CORS跨域问题方法 三.前端请求携带参数及Django后台如 ...

  6. 微信小程序日期转时间戳

    let date = '2019-10-14'; var repTime = date.replace(/-/g, '/'); var timeTamp = Date.parse(repTime) / ...

  7. kubernets资源预留

    一.  Kubelet Node Allocatable Kubelet Node Allocatable用来为Kube组件和System进程预留资源,从而保证当节点出现满负荷时也能保证Kube和Sy ...

  8. Mybatis系列全解(八):Mybatis的9大动态SQL标签你知道几个?提前致女神!

    封面:洛小汐 作者:潘潘 2021年,仰望天空,脚踏实地. 这算是春节后首篇 Mybatis 文了~ 跨了个年感觉写了有半个世纪 ... 借着女神节 ヾ(◍°∇°◍)ノ゙ 提前祝男神女神们越靓越富越嗨 ...

  9. JVM-对象及对象内存布局

    目录 前言 类与对象 对象类二分模型 对象 对象内存布局 JOL工具 对象头 Mark Word 类型句柄 对象头与锁膨胀 无锁 偏向锁 轻量级锁 重量级锁 重量级锁降级 实例数据 填充 对象生命周期 ...

  10. 什么是内存对齐,go中内存对齐分析

    内存对齐 什么是内存对齐 为什么需要内存对齐 减少次数 保障原子性 对齐系数 对齐规则 总结 参考 内存对齐 什么是内存对齐 弄明白什么是内存对齐的时候,先来看一个demo type s struct ...