Apache Dubbo支持多种通信协议,官方默认为Dubbo协议,当用户选择HTTP协议进行通信时,攻击者可以利用该漏洞在目标网站上远程执行恶意代码,最终导致网站被控制、数据泄露等。据官方介绍,此次漏洞主要影响Apche Dubbo的以下版本:
- 2.7.0<= Apache Dubbo <= 2.7.4.1
- 2.6.0<= Apache Dubbo <= 2.6.7
- Apache Dubbo = 2.5.x
官方解决方案: 大批量升级风险大
Apache Dubbo官方建议用户网站升级到安全的2.7.5版本,以解决此漏洞。但这种方式比较激进,贸然大批量升级风险比较大,主要有以下两方面的原因:
第一,Dubbo历史比较久远,版本升级往往不平滑。很多客户很早就在使用Dubbo了,Dubbo在2014年停止维护过一次,中间很多客户切换到当当网推出的Dubbox,Dubbo在2017年重新进行维护,这些众多的历史版本和分支,涉及到很多的依赖包和中间件。从实践角度来讲,升级绝对不是简单替换一个jar包这么简单,可能会存在大量的不兼容的问题,需要逐步排查,才能成功升级。
第二,Dubbo服务数目较多,批量升级工作量大。早期使用Dubbo的客户,经过较长时间的微服务化的历程,目前服务数目已经比较多,其中包括核心服务,如果只升级部分,可能会出现不兼容情况,批量升级,工作量太大,而且涉及核心业务可能造成停服风险,是客户很难接受的。
轻舟解决方案:三重机制避免漏洞风险
轻舟微服务是一个基于开源技术栈、支持私有云或公有云等灵活IT架构的一站式云原生服务平台,包含微服务框架NSF,应用性能管理APM,容器平台NCS,分布式事务GTXS,API网关,PaaS中间件,业务监控,持续集成流水线CI/CD等八大组件构成。
其中和Dubbo关系比较紧密的是微服务框架NSF。
很多客户在使用开源微服务框架的时候,多采用上图左面的方式,所有服务管理与治理的功能全部需要自己开发,在业务代码之外开发量大。而且Dubbo和Spring Cloud有很多的配置,这些配置和代码逻辑散落在各个工程,每增加一个功能,需要所有的业务重新发布上线。
而轻舟微服务框架NSF,采用全栈字节码增强技术,0侵入,0性能损耗,纳管业务系统。服务管理与功能全部集中在agent中,开发仅需关注业务代码,二者代码级分离。并且提供统一的可视化动态治理界面,开发、运维职责独立分配,更新实时生效。
轻舟微服务框架NSF基于原生Spring Boot技术实现,能够兼容纳管Spring Cloud、Dubbo、Grpc、Istio等主流框架的应用系统,且提供易用性、可视化、安全性、人性化的可视化界面。
那轻舟微服务框架NSF如何解决这次Dubbo的漏洞问题呢?
第一,轻舟微服务框架NSF提供外部服务及服务之间的认证和鉴权机制,可以灵活配置某个服务是否开启认证鉴权开关,一旦开启,客户端请求被Agent拦截,会去NSF进行认证鉴权,只有通过了,才放行,让请求到达服务端,对于一些核心业务,可以启用认证鉴权机制,只让信任的服务调用,可大幅度减少风险。
第二,轻舟微服务框架NSF可以灵活配置服务之间调用的黑白名单,可以用服务名,也可以使用IP地址段。一方面只有信任的服务及IP段可以访问某些服务,另一方面,一旦发现风险,可以在界面上及时配置,Agent会瞬间下发策略,将风险及时拦截。
第三,从长期来看,Dubbo有Bug还是应该升级的,升级需要有一定的策略,根据服务之间的依赖关系逐层分批升级,从而可以把控风险。使用轻舟微服务框架NSF,可以在界面上看到服务之间的动态依赖关系,可以根据这个依赖关键,进行逐步的升级。
最佳实践建议:面对漏洞,风险可控
轻舟是针对微服务架构的全栈解决方案,除了产品之外,网易在自身业务落地的过程中,也总结出来了全方位的最佳实践,可以提供咨询服务。针对Dubbo的漏洞问题,轻舟微服务团队给出了以下最佳实践建议,即便Dubbo有漏洞问题,也能及时的控制风险。
第一,容器层:在容器层最佳实践中,里面有很重要的两条,一是容器镜像尽量小,删除不必要的工具,这样即便部署在容器里面的Dubbo服务被侵入,容器内部也没有什么命令可以执行。二是不要使用privileged运行容器,这样容器即便被侵入,也无法逃逸到宿主机中。
第二,Kubernetes层:对于Kubernetes,不建议所有的Pod都默认互通,而是启用适当的NetworkPolicy进行隔离。
第三,微服务层:Dubbo服务的升级的确是很头疼的事情,因为服务多,依赖关系复杂,但是如果秉承以下的最佳实践,则升级会轻松一些。
规范之一:仅仅单向调用,严禁循环调用。微服务拆分后,服务之间的依赖关系复杂,如果循环调用,升级的时候就很头疼,不知道应该先升级哪个,后升级哪个,难以维护。
因而层次之间的调用规定如下:
- 基础服务层主要做数据库的操作和一些简单的业务逻辑,不允许调用其他任何服务;
- 组合服务层,可以调用基础服务层,完成复杂的业务逻辑,可以调用组合服务层,不允许循环调用,不允许调用Controller层服务;
- Controller层,可以调用组合业务层服务,不允许被其他服务调用。
如果出现循环调用,例如A调用B,B也调用A,则分成Controller层和组合服务层两层,A调用B的下层,B调用A的下层。也可以使用消息队列,将同步调用,改为异步调用。
规范之二:接口数据定义严禁内嵌,透传微服务接口之间传递数据,往往通过数据结构,如果数据结构透传,从底层一直到上层使用同一个数据结构,或者上层的数据结构内嵌底层的数据结构,当数据结构中添加或者删除一个字段的时候,波及的面会非常大。
因而接口数据定义,在每两个接口之间约定,严禁内嵌和透传,即便差不多,也应该重新定义,这样接口数据定义的改变,影响面仅仅在调用方和被调用方,当接口需要更新的时候,比较可控,也容易升级。