You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
15 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 11 | 插件漏洞:我的代码看起来很安全,为什么还会出现漏洞?
你好,我是何为舟。
在讲[反序列化漏洞](https://time.geekbang.org/column/article/182421)的时候我们说过这个漏洞其实就存在于Fastjson、Jackson等知名的JSON解析库中跟你自己写的代码没有太多关系所以极难掌控。也就是说在开发应用的过程中尽管你的代码很安全了黑客还是能够通过插件漏洞对应用发起攻击我文中提到的插件是第三方的插件、依赖库、工具和框架等的统称
说到这儿,想不想测试一下你的插件是否安全?在这里,我准备了几个问题,你可以看看自己是否对所用的插件了如指掌。
* 你所使用的所有插件的版本是什么?(包括前端和后端,直接引用和间接引用)
* 你所使用的这些插件,是否存在漏洞,是否不被维护了,是否被废弃了?
* 你所使用的这些插件,会在哪些地方发布更新信息和漏洞信息?
* 你所使用的这些插件,是否会定期更新?你是否会对更新插件进行完整的测试?
* 你所使用的这些插件,在安全方面,有哪些配置需要关注?
对于这些问题,如果你还没办法很快回答上来,那你的应用很有可能要受到插件漏洞的威胁了。所以,我接下来要讲的内容,你要认真听了。
## 为什么要重视插件漏洞?
在谈论安全漏洞的时候你应该经常会听到“0 day”中文译为“零日”这个词。到底什么是“0 day”呢“0 day”即在插件发布修复漏洞的安全补丁之前黑客就已经知道漏洞细节的漏洞。换一句话说“0 day”就是只有黑客知晓的未公开漏洞。
说到这里,不知道你有没有听说过一个叫作[脏牛](https://dirtycow.ninja/)[CVE-2016-5195](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-5195)的Linux系统漏洞这个漏洞可以实现提权操作也就是让低权限的用户获得较高权限。在这个漏洞被公开曝出之前它已经存在于Linux系统中长达9年了直到现在仍然有很多黑客通过这个漏洞获取较高的系统权限。
而这其实就是一个“0 day”漏洞。因为只有黑客知道这个漏洞而我们连这个漏洞是什么都不知道所以“0 day”几乎无法防御。除此之外“0 day”还具备极高的攻击有效性可以说只要应用使用了对应的插件黑客几乎“战无不胜”。甚至在黑市上“0 day”漏洞都可以作为一种资产在黑客间进行交易。
那除了“脏牛”,还有两个知名的插件漏洞,不知道你有没有耳闻。
一个是[心脏滴血](https://news.netcraft.com/archives/2014/04/08/half-a-million-widely-trusted-websites-vulnerable-to-heartbleed-bug.html)[CVE-2014-0160](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160)。心脏滴血是加解密插件OpenSSL中的漏洞OpenSSL曾为所有HTTPS网站提供数据加密保护。这个漏洞让任何人都可以通过网络读取OpenSSL系统内存中的数据解密所有的加密流量。这让当时至少一半的HTTPS站点都受到了影响。
另一个是Structs 2的漏洞[CVE-2017-5638](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5638)。这个漏洞在2017年导致美国三大信用机构之一的[Equifax](https://resources.whitesourcesoftware.com/blog-whitesource/the-equifax-breach-who-s-to-blame)泄露了1.4亿用户的姓名、SSN美国身份证号、生日和地址等。受影响的用户相当于近一半的美国人口。我们在开篇词里也有提过这里我就不多说了。
总之对于应用来说不只代码本身会产生漏洞除了代码之外的一切也都有可能出现漏洞。从提供加解密功能的工具OpenSSL到提供网络服务的框架Structs 2甚至是基础的操作系统Linux都有可能出现各种漏洞。插件漏洞既能够破坏插件本身的功能也能让黑客以插件为跳板实现控制整个应用甚至是服务器。
## 如何建立插件漏洞的防护体系?
那我们该如何对插件漏洞进行防护呢?实际上,修复和维护插件漏洞的过程,就是在和黑客竞赛的过程。业内有大量专业的安全研究人员,专注于对这些插件漏洞进行研究。因此,我们可以使用行业内的现有研究成果,来帮助我们提升插件的安全性,建立插件漏洞的防护体系。
具体来说,我总结了三步,但其实这三步并非完全递进的。你可以参考这三步的做法,看看哪些你已经做到了,哪些还没有做过,可以试一试。
### 第一步:整理插件,剔除无用插件
避免插件漏洞威胁的第一步自然是了解自己的应用都使用了哪些插件。我就以Java中的Maven插件管理工具为例详细说一下整理和剔除插件的过程。
如果使用Maven作为插件管理工具的话你一定会先通过POM文件去找到自己所使用的插件即所有的Dependency。但是Dependency只是你的应用中直接使用的插件这些插件本身也会引用很多其他插件。所以大部分应用的插件依赖树十分复杂那你该如何整理全部的插件呢
首先,你可以通过[Maven Dependency Plugin](http://maven.apache.org/plugins/maven-dependency-plugin/)帮助自己自动分析插件依赖树。除了展示出当前Maven工程中所有的使用插件Maven Dependency Plugin还会对插件的使用情况做进一步的分析帮你找出在POM中却没在代码中使用的插件。这样你就可以对这一类无用的插件引用及时剔除自然也就能够减少插件漏洞出现的可能性。
比如,在下面这个分析结果中,通过`mvn dependency:analyze`的分析我们发现了JUnit和Logback这类“虽然被引用但却没有被使用”的插件。既然没有被使用那我们就可以很放心地进行删除了。
```
mvn dependency:tree dependency:analyze
...
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ client ---
[INFO] com.coveros:sample-maven:jar:0.0.1-SNAPSHOT
[INFO] +- junit:junit:jar:4.11:test
[INFO] | \- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] +- org.slf4j:slf4j-api:jar:1.7.5:compile
[INFO] \- ch.qos.logback:logback-classic:jar:1.0.13:test
[INFO] \- ch.qos.logback:logback-core:jar:1.0.13:test
...
[INFO] --- maven-dependency-plugin:2.8:analyze (default-cli) @ client ---
[WARNING] Unused declared dependencies found:
[WARNING] junit:junit:jar:4.11:test
[WARNING] ch.qos.logback:logback-classic:jar:1.0.13:test
...
```
### 第二步:管理插件补丁更新
一旦某个插件出现漏洞,通常插件的运维方都会尽快推出补丁。有的公司还会设立专门的部门和人员进行补丁管理的工作。一旦出现漏洞和补丁,公司会先评估漏洞的严重性,然后设定打补丁的优先级,推动研发人员进行更新操作。
所以,建立插件防护体系的第二步,就是要知道你有哪些插件需要更新。但是,在实际工作中一个应用随便就依赖几十个插件,你当然没办法一个一个去查询插件的更新状态了。那[Version Maven Plugin](https://www.mojohaus.org/versions-maven-plugin/)就是用来帮你检查版本更新的一个工具。你可以看到,在下面的分析结果中,通过`mvn version:display-dependency-updates`这个命令我们就能发现JUnit有一个新的4.11版本。
```
mvn versions:display-plugin-updates versions:display-dependency-updates
...
[INFO] --- versions-maven-plugin:2.1:display-plugin-updates (default-cli) @ sample-maven ---
[INFO]
[INFO] The following plugin updates are available:
[INFO] maven-deploy-plugin ...................................... 2.7 -> 2.8
[INFO]
[INFO] All plugins have a version specified.
[INFO]
[INFO] Project defines minimum Maven version as: 3.0
[INFO] Plugins require minimum Maven version of: 3.0
[INFO]
[INFO] No plugins require a newer version of Maven than specified by the pom.
[INFO]
[INFO]
[INFO] --- versions-maven-plugin:2.1:display-dependency-updates (default-cli) @ sample-maven ---
[INFO] The following dependencies in Dependencies have newer versions:
[INFO] junit:junit ............................................. 4.10 -> 4.11
...
```
尽管Version Maven Plugin也提供自动更新的功能不过我更推荐你手动进行更新。因为对于插件的版本变更其兼容性并没有保证而且你也无法保证插件在更新的过程中不会对它原本的功能产生影响。
那使用了补丁管理工具之后我们就可以完全放心了吗当然不是。补丁管理中依旧存在一些问题我这里从3个方面帮你梳理了一下你可以作为了解。
* 补丁可用性:并不是所有的插件漏洞,都能有最新的补丁进行及时的更新和维护。很多时候,运维人员会面临一个已知的漏洞,但无补丁“可打”的窘迫局面。
* 覆盖面不全:实际上,并不是所有语言都能够很好地进行插件分析工作,这也就导致运维人员无法掌控公司内所使用的所有插件。这个时候,必然会产生一定的漏洞疏忽。
* 更新时间延迟:为了提高打补丁的效率,补丁管理一般会按月或者按季度进行集中的打补丁工作。而在这个期间,公司的应用就会处于无保护的状态。
为了解决这些问题虚拟补丁的概念就被提出了。所谓虚拟补丁就是在不对应用插件进行升级的情况下有效阻止攻击流量。实现的原理也很简单即在前置的网络或系统中对针对插件漏洞的攻击流量进行检测和拦截即可大部分防火墙、IPS等安全防御工具都会提供虚拟补丁的功能。比如2017年[永恒之蓝](https://baike.baidu.com/item/%E6%B0%B8%E6%81%92%E4%B9%8B%E8%93%9D/4951714?fr=aladdin)肆虐的时候防火墙会直接封禁445端口请求就相当于给所有的Windows系统打上了虚拟补丁。然后只需要等到所有Windows都真正更新补丁之后再放开对445端口的限制即可。
### 第三步:使用公开漏洞库
最后,你还需要知道,在你所使用的插件中,是否已经存在了公开的漏洞。
我在讲解知名插件漏洞的例子中提到了一些漏洞的编号脏牛CVE-2016-5195、心脏滴血CVE-2014-0160和Structs 2的漏洞CVE-2017-5638。细心的同学可能已经想要问了那这些编号是怎么来的呢又代表了什么含义呢
实际上每个漏洞的编号都是该漏洞在公开漏洞库的唯一编号。我提到的这三个编号开头都是CVE也就是说这三个编号的信息都存在于[CVE](https://cve.mitre.org/)Common Vulnerabilities & Exposures公共漏洞和暴露这个公开漏洞库中你可以根据漏洞的唯一编号在CVE中快速地找到这个漏洞相关的信息包括受影响的版本、可能造成的影响、修复的方法及补丁等。
除了CVE之外公开的漏洞库还包括[CWE](https://cwe.mitre.org/)Common Weakness Enumeration通用缺陷列表、[CVSS](https://www.first.org/cvss/)Common Vulnerability Scoring System通用漏洞评分系统、[NVD](https://www.nist.gov/programs-projects/national-vulnerability-database-nvd)National Vulnerability Database国家信息安全漏洞库以及[CNVD](https://www.cnvd.org.cn/)(China National Vulnerability Database中国国家信息安全漏洞库
每当漏洞库中新曝出一个漏洞时,你需要分析这个漏洞所涉及的插件:是否在公司中有被使用;公司中使用的,是否是受影响的版本;这个漏洞会产生哪些危害等等。这样,你才能够尽快地修复各类已知的插件漏洞,降低应用被黑客攻击的可能。
那实际工作中,我们其实也可以借助工具,自动化地完成匹配公开漏洞库的工作。[OWASP Dependency-Check](https://jeremylong.github.io/DependencyCheck/)是一款专门进行插件漏洞检测的工具。它会将工程内的插件和公开的漏洞库进行比对。最终会生成一个网页形式的报告使你对工程中的插件漏洞一目了然了。下图就展示了如何通过OWASP Dependency-Check发现一个3.2.1版本的Commons-Collections的高危漏洞。
![](https://static001.geekbang.org/resource/image/38/05/383ca5b55e749be2ba11820ad4542605.png)
同理在其他语言中也会存在类似的插件管理工具。比如对于JavaScript中的插件我们可以使用[Retire.js](https://github.com/retirejs/retire.js/)进行整理。
总结来说,我们在建立插件漏洞的防护体系时,会使用这些自动化管理工具完成这样三件事情:
* 统计你的应用中引用了哪些插件
* 管理这些插件中是否有版本更新
* 检测这些插件是否存在已知的漏洞
根据这些信息,你就能够对应用中的插件安全性,有一个比较完整的认知了。接下来,在实际使用的过程中,我们根据漏洞的更新情况,有针对性地修复即可。
## 总结
好了,今天的内容讲完了。我们来一起总结回顾一下,你需要掌握的重点内容。
在开发应用的过程中,我们总是需要引入各种第三方插件。而这些第三方插件的漏洞,尽管看起来很容易解决,只需要一直使用最新的插件,并保持更新即可。但是,往往因为版本更新繁琐,且无法带来业务收益,很多公司都会因此忽视插件漏洞的防护工作。所以,在应用中存在一个好几年前的插件漏洞并不奇怪。
提高版本更新的效率、避免插件漏洞主要可以分三个步骤首先我们可以使用插件分析工具来了解应用中包括了哪些插件然后可以通过补丁管理制度和虚拟补丁来推进对插件漏洞的管理和修复工作最后我们可以对比公开漏洞库比如CVE等中的最新漏洞及时修复漏洞降低被黑客攻击的可能。
好了,我把这一讲的重点内容梳理了一个脑图。你可以用它来查漏补缺,也可以自己来梳理看看,加深印象。
![](https://static001.geekbang.org/resource/image/64/72/6483102d652caf01c72dd5dd3602e572.jpg)
## 思考题
最后,给你留一个思考题。
你可以尝试对你的应用作一次插件分析看看会不会出现已知的安全漏洞。除此之外你还可以对应用的外部依赖数据库、Web服务、操作系统等进行一次调查在当前版本中是否存在公开的漏洞
欢迎留言和我分享你的思考和疑惑,也欢迎你把文章分享给你的朋友。我们下一讲再见!