Blog

Blog

PHODAL

依赖孪生:低成本的依赖安全方案

最近我在阅读一本安全方案的书《零信任网络:在不可信网络中构建安全系统》,它让我对应用的安全有了一次新的升级。当然了,这又是一本昂贵的,字数不多的 O'Reilly 的书。

在看这本书的期间,我突然有了一个新的安全实施方案: 依赖孪生——针对于中小型 IT 组织的依赖方案。(PS:其实这只是吹吹而已,并没有那么夸张)。所以,我就顺手写了一篇文章,记录一下相关的实践和模式。

WHY

在构建软件系统时,软件的一部分依赖于另外一部分,就产生了依赖关系。(『持续交付:发布可靠软件的系统方法』)除了,组织内部的软件依赖之外,一个为了快速满足于业务系统的软件系统,便会充斥大量的三方依赖——受益于开源软件的发展。

对于大型组织来说,依赖的管理及期风险控制变成一个极其重要的话题,它涉及到法律风险及安全漏洞两方面的问题。这里的法律风险指的是依赖相关的软件协议、出口限制等带来的问题。在我们引入软件包的时候,开源协议带来的风险问题可以人为地降低。而依赖的安全问题,则不是一件容易的事情。尽管已经有商业的软件,可以做这样的工作,但是对于大部分的企业而言,维护一个 IT 团队已经不是一件容易的事。

依赖管理之所以成为新的关注点是因为依赖地狱、安全风险。

难以追踪的多重依赖

谈到多重依赖的时候,不得不谈及依赖地狱。

依赖地狱,是指在操作系统中由于软件之间的依赖性不能被满足而引发的问题。1

依赖地狱有多种类型1

  • 依赖过多。一个软件包可能依赖于众多的库,因此安装一个软件包的同时要安装几个甚至几十个库包
  • 多重依赖。指从所需软件包到最底层软件包之间的层级数过多。这会导致依赖性解析过于复杂,并且容易产生依赖冲突和环形依赖。
  • 依赖冲突。即两个软件包无法共存的情况。除两个软件包包含内容直接冲突外,也可能因为其依赖的低层软件包互相冲突。因此,两个看似毫无关联的软件包也可能因为依赖性冲突而无法安装。
  • 依赖循环。即依赖性关系形成一个闭合环路,最终导致:在安装A软件包之前,必须要安装A、B、C、D软件包,然而这是不可能的。

依赖冲突和依赖循环是我们在引入软件包的问题,这个问题对于那些运行时依赖的语言来说比较常见,诸如于 Java、Ruby、Python 等。而对于编译时依赖的语言,如 JavaScript,这个问题并不会那么痛点。为此比较常见的痛点便是依赖过多多重依赖

而多重依赖往往是经常出现安全漏洞的地方,如之前的 left-pad 事件。我们的项目依赖于 A,而 A 依赖于 B 库,而 B 库又可能依赖于 C 库。它会导致依赖的层层引用,导致我们无法人为地追踪每个库——这个问题在 JavaScript 社区特别严重(主要是 Node.js 相关)。

如下是 Angular CLI 生成的一个新的项目的依赖示例:

 "dependencies": {
    "@angular/animations": "~7.2.0",
    "@angular/common": "~7.2.0",
    "@angular/compiler": "~7.2.0",
    "@angular/core": "~7.2.0",
    "@angular/forms": "~7.2.0",
    "@angular/platform-browser": "~7.2.0",
    "@angular/platform-browser-dynamic": "~7.2.0",
    "@angular/router": "~7.2.0",
    "core-js": "^2.5.4",
    "rxjs": "~6.3.3",
    "tslib": "^1.9.0",
    "zone.js": "~0.8.26"
  }

从表面上来看,我们只依赖于 Angular 相比的几个组件,但是实际上它生成的依赖树是这样的:

Angular 新项目依赖树

:上图由 npm2dotGraphviz 生成。

安装过程风险

对于只是使用类库,如 Java 的 *.jar 往往不会有这个问题。而对于诸如 Node.js 服务端项目中的 NPM 来说,它存在一个 preinstallpostinstall 的过程,在这个过程中会运行依赖开发人员的预设脚本。诸如于 Standard JS 的广告问题,又或者是 core-js 的寻找工作:

Also, the author of core-js (https://github.com/zloirock) is looking for a good job -)

话说我真应该再写一篇文章:开源软件作者正在遭遇的收入困境。毕竟 core-js 的项目被 3,407,074 个项目依赖,而作者并没有因此带来太多的收入。还好,我已经放弃了用开源软件赚钱的方式。

在有了 NVM 的情况下,你并不会用 sudo 去执行 npm install 或者 yarn install,否则开发人员可以在脚本中添加一个 rm -rf /。不过,对于大部分前端项目来说,只是在客户端执行 npm install。哪怕是采用 Node.js 的系统来说,也只会在容器里运行 npm install

昂贵的商用解决方案

应对这些开源软件,便有了一系列的解决方案。诸如于 Black Duck 或者是 SonarQube:

Black Duck,是当前在这一方面最全面的开源组件、漏洞和许可信息数据库,Black Duck 软件组成分析解决方案和开源审计为您提供必要的洞见,用于跟踪代码中的开源、降低安全性和许可合规性风险,并使用您现有的 DevOps 工具和流程自动实施开源策略。

当然了,对于还有 SonarQube 也是一个不错的方案,只是 SonarQube 更关注于代码质量。对于大型组织来说,这都是小问题。而中小型组织来说,要去维护这些基础设施并不是一件容易的事。

为此,我们就有了依赖孪生这样扯淡而又有意思的解决方案。

WHAT

依赖孪生(dependency twins,依赖映射 depencecy mapping)是将项目依赖状态信息(包括元数据,配置和条件)用模拟真实的项目(类似于内部环境的双胞胎)的形式,存储在第三方的信息化平台上来,以用于进行依赖的安全检测。稍有不同的是,它是免费的,并且你还不需要开源你的代码。

即,我们构建一个虚拟的项目,在这个项目中只存储依赖信息,如软件包的名称和版本,随后将运行在提供这样功能的平台上,比如 GitHub。它既可以帮助我们检查依赖,又可以保存代码的安全性。

所以说,这是一个适用于小型组织的方案。

HOW

  1. 上传项目的依赖到 GitHub 的私有私有私有项目中
  2. 查看项目的 Security Alerts
  3. Done

其它

你还有什么更好的 idea 吗?


  1. https://zh.wikipedia.org/wiki/相依性地狱 

关于我

Github: @phodal     微博:@phodal     知乎:@phodal    

微信公众号(Phodal)

围观我的Github Idea墙, 也许,你会遇到心仪的项目

QQ技术交流群: 321689806
comment

Feeds

RSS / Atom

最近文章

关于作者

Phodal Huang

Engineer, Consultant, Writer, Designer

ThoughtWorks 技术专家

工程师 / 咨询师 / 作家 / 设计学徒

开源深度爱好者

出版有《前端架构:从入门到微前端》、《自己动手设计物联网》、《全栈应用开发:精益实践》

联系我: h@phodal.com

微信公众号: 最新技术分享

标签