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. NGK钱包真的安全吗?

    对于数字资产持有者而言,资产的安全永远是首要的,因而数字钱包的安全性显得尤为重要.数字钱包分为冷钱包和热钱包两种.热钱包叫做在线钱包,而冷钱包被称为离线钱包,也叫硬件钱包.数字钱包一旦被盗,被追回的概 ...

  2. PAA子公司在印度印度成立

    近日PAA房产又有大动作啦!在一片期待中,印度分公司正式成立!这是集团继泰国.越南.韩国.上海.成都.中国香港.中国台湾等分公司成立之后的又一扛鼎力作,更是PAA集团全球化战略布局的重要举措. 印度分 ...

  3. 三种远程部署war包检测

    简介 远程部署漏洞属于服务器.中间件配置问题,攻击者可通过远程部署漏洞获取系统权限,远程部署漏洞经常出现在Tomcat.Jboss.Weblogic等web容器之上. 0x01 ### tomcat部 ...

  4. Elasticsearch 分片集群原理、搭建、与SpringBoot整合

    单机es可以用,没毛病,但是有一点我们需要去注意,就是高可用是需要关注的,一般我们可以把es搭建成集群,2台以上就能成为es集群了.集群不仅可以实现高可用,也能实现海量数据存储的横向扩展. 新的阅读体 ...

  5. 必知必会之 Java

    必知必会之 Java 目录 不定期更新中-- 基础知识 数据计量单位 面向对象三大特性 基础数据类型 注释格式 访问修饰符 运算符 算数运算符 关系运算符 位运算符 逻辑运算符 赋值运算符 三目表达式 ...

  6. GMS的概述

    1 GMS GMS全称为GoogleMobile Service,即谷歌移动服务. GMS是Google所提供的一系列移动服务,包括开发用的一系列服务和用户所用的Google Apps. Maps与L ...

  7. wxWidgets源码分析(6) - 窗口关闭过程

    目录 窗口关闭过程 调用流程 关闭文档 删除视图 删除文档对象 关闭Frame App清理 多文档窗口的关闭 多文档父窗口关闭 多文档子窗口关闭 窗口的正式删除 窗口关闭过程总结 如何手工删除view ...

  8. 看完我的笔记不懂也会懂----Node.js

    Node.js 学习 - 命令行窗口 - 进程与线程 - ECMAScript的缺点 - Node模块化 - Node中的全局对象 - 包 package - NPM包管理器 (Node Packag ...

  9. Deep Unfolding Network for Image Super-Resolution 论文解读

    Introduction 超分是一个在 low level CV 领域中经典的病态问题,比如增强图像视觉质量.改善其他 high level 视觉任务的表现.Zhang Kai 老师这篇文章在我看到的 ...

  10. Linux添加普通权限账号并授予root权限

    命令创建账号和密码 adduser Mysticbinary #添加一个Mysticbinary用户 passwd Mysticbinary # 输入密码 授予可以切换root的权限 修改/etc/s ...