如何阻止下一次心脏出血漏洞
一、引言
基于OpenSSL的心脏出血漏洞被认为是CVE-2014-0160的严重问题,OpenSSL被广泛的应用于SSL和TLS插件上。本文用对心脏出血漏洞的解释来说明这个漏洞是怎么被利用的。
本文中研究了抗心脏出血漏洞及其相似漏洞的专用工具和技术。我首先通过简单的测试来分析为什么很多的工具和技术不能发现这些漏洞,这样可以使我们更能了解到为什么之前的技术不能发现这些漏洞。我还要概括总结要点来减少这些的问题。本文不介绍如何编写安全软件,你可以从我的书《Secure Programming for Linux and Unix HOWTO》或是其他的著作中学习到这点,本文中认为您能开发软件。
我的目的是为了帮助防止类似漏洞的出现,从而提高安全软件的开发能力。正如Orson Scott Card’s Ender’s Game中的虚幻人物Mazer Rackham所说的“这里没有老师,只有敌人…只有在敌人那里你才能了解到自己的弱点。”让我们来了解这些漏洞,然后可以避免相似的漏洞再次出现。
二、为什么这个漏洞不能更早的被发现?
这个OpenSSL漏洞是由一个很熟悉的问题引起的,这个关键的问题就是缓冲区读溢出,由于不正确的输入导致。这些都是很常见的问题,很多的工具是专门用来查找这方面的问题,会使用很多工具对OpenSSL进行定期检查。
Kupsch和Miller专门查找了心脏出血漏洞,在这个漏洞被发现之前,使用了很多的方法也没有发现这个漏洞,虽然很多人和工具都用来查找类似的漏洞。他们进一步认识到“心脏出血漏洞对当前的辅助软件提出了重大的挑战,而且我们不知道是否有工具能在这个漏洞被发现之前被使用。”我会强调一些其它的问题和我自己的一些观点。
2.1 静态分析
在没有执行这个程序时的静态分析。
最常用来寻找漏洞的静态分析工具是source code weakness analyzers,source code security analyzers, static application security testing,static analysis code scanners 和 code weakness analysis tools。每个源代码分析工具是通过使用类型匹配的方法来寻找漏洞的。有很多的报告可以评估这些工具。
然而,在之前的时间里使用静态分析工具没有发现这个漏洞:
1、Coverity:Coverity没能在心脏出血漏洞公布之前发现这个漏洞。他们正在通过努力来提高他们的工具的质量,从而在将来能够发现相似的漏洞,使用了一些有趣的新启发方法。
2、HP/Fortify: HP/Fortify已经公布了一些心脏出血漏洞的描述,但是我没有任何的证明能说明他们的静态分析工具在漏洞公布前就发现了这个漏洞,在漏洞被公布后,他们确实是更改了他们的动态测试软件包,但是和之前的不同。在专门讨论这个问题时,他们没有证据让我相信他们的工具真的在心脏出血漏洞被公布之前就发现了这个漏洞。
3、Klocwork: Klocwork在正常的配置下没有能够侦测到这个漏洞。
4、Grammatech: Grammatech 的CodeSonar同样没有侦测到这个漏洞。他们也是通过实验来提升能力,以便在以后能够发现相似的漏洞。
最主要的争议就是这些工具都不能保证能够发现所有的漏洞,甚至不能保证发现特定类型的漏洞。很糟糕的是这些术语很混乱,所以我们首先要搞清这些术语的意思。
本文中在分析软件时,使用的工具不能找到所有的漏洞,但是我找到了这个分析软件的不足。在以前的文章中,很多人使用unsound来描述那些不能找到所有漏洞的来查找漏洞的工具。例如Bessey等人在分析Coverity的静态分析工具,并且说:“像PREfix产品,我们也使用unsound。”我们的产品并没有证明说这是没有错误的,而是尽我们的能力来发现这些问题。这项研究工作中存在很大的争议,虽然它几乎已经成为商业软件和研究项目的实际工具基础。一个unsound术语会导致混乱,因为人们使用program checkers,它使用术语unsound来代替不同的意思。在一个博客上解释了为什么相同术语会有两种相互矛盾意思。“大多数的program checkers来证明定律的程序。特别情况下,主要的目的是在某个方面来证明程序的正确性。一个定律的证明是来证明这个定律的正确与否…人民在程序检查过程中习惯了使用这种做法,所以他们没有考虑bug的存在。但是一个bug的发现者不是要证明这个程序是不对的,而是用来证明有bug存在,使得他们报告了发现的bugs,它们就都变成了真正的bug,如果没有错误,将会忽略bug,因为他们不能证明是否正确。”
本文中我使用了NIST SAMATE SATE V Ockham Sound Analysis标准来消除混乱,在NIST SAMATE用语中,工具是不能发现所有漏洞的,从而证明程序是不完备的。下面来说明NIST是怎么区分程序的可靠性和完整性:“一个网站的代码可能会出问题,一个有bug的网站会有一系列问题,这就是说一些输入会导致问题。一个没有bug的网站不会出现一些列问题,就是说它是安全的或是没有漏洞的…这些可以从一个网站的报告中得知。或者说,一个网站有特殊的问题或是一个网站没有问题…可靠就意味着每一个发现都是正确的。没有必要使用工具产生每个网站的报告;这是完整的。”
为什么那么多的源代码分析工具是不完整的?首先,大多数的程序语言不是很容易能被分析的。其次,大多数的软件使用静态分析工具来分析也是很不简单的。最后,完整的分析工具要求更多的人来应用在程序上。相反,不完整的分析工具能够立刻应用到程序上。他们成功的使用启发的方法来鉴定漏洞和在有限的时间里来完善分析。但是,这里会有重要的警告:不完整的代码分析工具常常会漏掉漏洞。
心脏出血漏洞是一个鲜明的使用不完全的启发方法不能发现的重要漏洞的例子,不能发现这个重要漏洞的最主要原因就是OpenSSL代码很复杂;多个层次的间接寻址和超出了工具的分析能力,从而不能发现漏洞。局限性和深层次存在的原因是C, C++和Objective-C都很难使用静态分析;像指针更难使用静态管理。这并不是意味着静态分析工具就是没用的,静态分析工具能够测试软件在大量的输入后的表现,工具的启发原理会限制错误报告的出现次数。但是更重要的是不完整的静态分析工具使用了启发原理后,在分析大的漏洞时会出现错误。
2.2 动态分析
动态方法就是使用特定的输入来运行一个程序并试着发现漏洞。
动态分析局限性是它不能使用时间表来测试任何程序。如在一个琐碎的程序中加入了64bit的整数,会有2128种可能的输入,测试这些输入就要使用13.5十万亿亿年的时间。甚至大规模的并行计算也不能解决这个问题。现实中的程序要比这复杂的多,因此动态方法不能体现一个程序的安全性;他们只能显示在测试中存在漏洞。
但是这并是意味着动态方法就是没有用的。动态方法在提升安全性上是很有用的,但是要了解到他们的局限。
让我们来分析我们广泛使用的两种方法,但是不能发现心脏出血漏洞: mostly-positive测试和fuzzers。
2.2.1 mostly-positive自动测试套件
一个方法是开发一个强大的自动化测试套件。Eric S. Raymond和一些其他人在研究心脏出血漏洞时,他的表述为:“我认为很多人都认为这个测试套件不能很好的工作…我以前学到了尽量去推进传统方法来完成你不能达到的程度。”我同意他的观点,一个好的自动化测试套件是很强大的,特别是应用于非安全性缺陷时。如果你没有或是开发一个,就完全的停止,我们表示同意。
但是,测试套件能否发现心脏出血漏洞要依靠你是怎么开发的这个套件。很多的开发人员都开发了测试套件,这个套件主要是我说的“mostly-positive”测试套件,它可能不能发现心脏出血漏洞。后面我将会讨论negative测试,这种测试方法可能会有作用,但是我们要知道为什么一般的测试方法不能做到。
很多的开发者和组织者专门测试了正确的输入时会发生什么。当你这样思考时就更有意义;一般的使用者都会抱怨在正确的输入时是否会没有正确的输出,并且大多数的使用者不会测试在不正确的输入时程序会有什么结果。如果你的目的是很快的分辨出问题,在大多数的情况下,在正确的输入时人们会努力控制能够预测的错误条件。很多的开发人员不能思考到当入侵者发送精心设计的输入来利用程序时会发生什么。
我会使用mostly-positive测试套件的方法来测试在正确的输入时会发生什么。不幸运的是,在很大程度上,今天的软件入侵测试套件都是mostly-positive。都在关注开发mostly-positive测试套件的测试。
1、Test-driven development(TTD)是一个软件开发过程,“开发者写了一个自动测试工具来提升和增加新的功能,之后使用最少数量的代码来通过测试,和最终生成新的代码的接受标准。”通常情况下这些测试是用描述一个新功能要做什么,而不是他们不能做什么。
2、当很多的标准链接在一起,交互式测试就会决定他们是否能够链接和分享数据。交互式测试能够很好的帮助开发者来提高一个协议标准。但是其他的实施方法也能遵守这个规则,其他的实施方法不能够完成“什么不发生”的测试。
mostly-positive测试实际上对于安全软件来说是没有用的。mostly-positive测试一般不能测试正确的事物。对于心脏出血攻击和其他的攻击,攻击者发送数据用不是平时用的格式。TTD和交互式测试都是好工具…但是你需要加强他们来改善安全软件。
代码覆盖工具对漏洞的发现没有任何的帮助。一个开发者可能会运行代码覆盖工具来看下哪些程序没有被测试,之后增加测试来达到大部分的代码被测试。当测试套件测试了80%-90%的代码时,很多人会很高兴;一般很少会达到100%的覆盖。测试覆盖工具有某种安全价值,例如,他们有时能够侦测到等待出发者的恶意软件,他们也能够核查是否有特别的程序能够正确的运行。但是使用典型的代码覆盖工具测试到100%的覆盖,不能对抗心脏出血漏洞。心脏出血漏洞缺少恰当的输入验证。基本上,一个代码覆盖工具不能注意到丢失的代码;只能注意到没有测试的代码。
我要说在OpenSSL里也不会有例外出现,又如在苹果的iOS设备上运行SSL/TLS得到了错误的结果时,也能通过mostly-positive来证实它的测试。在这个漏洞中,SSL/TLS库接受了有效的证明。然而,没有人验证这个库能拒绝某些无用的验证。如果你只是测试是否有效的数据会产生有效的结果,你就不能发现安全漏洞,因为大多数的攻击都是在基于程序没有准备好的时候输入。
如果你开发的套件能使用我在下面描述的方法,你能够通过一个好的测试套件来发现这个漏洞。首先,让我们来研究fuzzing。
2.2.2 Fuzzers 和fuzz测试
Fuzz测试是一个随机输入,之后发送到程序测试去看是否出现不渴望的过程。进行fuzz测试的软件叫Fuzzers。
Fuzz测试同传统的测试不同,在传统的测试过程中,你会有一个给定的输入组,并且你知道每个输入对应的输出情况。传统测试会随着测试数据的增加而变得更复杂,因为你要预测渴望的输出结果。决定输出想要的输出结果是一个Oracle机制。使用一个Oracle的数据作为输入的问题被叫做Oracle problem。
Fuzz测试处理不同的Oracle problem,因为它只是在试图侦探能使程序崩溃的问题。这就是使它在Fuzz测试中输入更多的测试数据,即使输出测试更不准确。Fuzzing测试方法是1988年Barton Miller在University of Wisconsin开发的。在http://pages.cs.wisc.edu/~bart/fuzz/上有更多的有关fuzz测试的信息。
Fuzzers经常用来发现安全漏洞,因为他们能够测试大量不可想象的输入。特别是,Fuzzers常用来发现输入验证的问题,心脏出血漏洞就是在输入验证错误的基础上产生的。但是典型的Fuzzers不能发现心脏出血漏洞,因为:
1、心脏出血漏洞是由于缓冲区读入溢出,而不是缓冲区写入溢出的漏洞。大多数的Fuzzers只是发送大量的数据和寻找程序的崩溃。但是,当缓冲区写入溢出常常会导致崩溃,缓冲区写入溢出在正常的环境里是不会崩溃的。在Fuzzing过程中,甚至会使用一些对策来解决写入溢出,而不是读入溢出,如canary-based保护方法和非执行堆栈。可靠性不是很大的问题,因为存在方法是出入溢出导致崩溃,或使用其他的测试工具来测试…这会给我们带来第二个问题。
2、OpenSSL包括它的内存分配路径,并且除非使用特别的调试方法,不然我们会经常使用他们。更糟糕的是这些特别的方法不能正常工作。特别是,OpenSSL使用它自身的应用程序管理缓存来提高性能时,而不是简单的依靠内存管理路径。这种应用程序管理缓存可以阻止许多典型的缓存例程,包括测试工具如electric fence、valgrind和address sanitizer。这就意味着使用fuzz测试来测试缓存的路径问题时,测试会忽略一些特殊的情况。
因为加密技术能在很大程度上减少fuzz测试的无效性,除非fuzzer有密码和专门用来袭击的密码库。有一些fuzzing不能在OpenSSL和一些密码库下严格执行的推测应该是正确的,然而,没有什么能阻止密码被fuzzers获取。除此之外,心脏出血漏洞甚至在没有密码的情况下被发现。因此,就是在读出溢出和OpenSSL使用自身的内存缓存分配路径的联合使用时,使fuzzing变的无效。
三、用什么来对抗类似心脏出血的漏洞?
这里有部分在先前可以对抗心脏出血漏洞的软件和工具,我会特别的介绍一些好用并且免费的自由开源、源代码软件。
首先是一些说明:
不要只用一种工具或一种技术来开发安全软件。开发安全软件要集合很多的方法,最开始要知道怎么开发安全软件。大多数的组织最初是使用简洁清晰的方法来开发安全软件,启用和注意编辑器的警告标志,使用源代码弱点分析工具,让多人进行研究,运行fuzzers,使用大量的自动入侵工具套件。如果你只是使用一种技术,你只能对抗上一次攻击而不是这次。例如,会大量的忽略掉警告标志,即使是警告标志不能发现心脏出血。那就是说,当攻击成功时,最重要的是怎么完善软件,攻击者可能如使用一样的方法来入侵软件。更好的改进也能对抗其他的攻击。
这不存在一种类型的工具和技术的列表,不同的工具有不同的用途。可以在[BAH2009] [NIST]上了解更多关于各个类型的工具和技术。我创建了这个特别的列表,但是我要尽量清楚我的意思。
先前没有一个明确和完整的用来发现心脏出血漏洞的工具和技术的列表,我很想做一个,我希望得到更好的建议。
以上是一些说明,先前是什么在对抗这个漏洞的,为了完成这个,我已经大致的完成了这个列表,用最简单的方式介绍他们。这是最粗略的,会有一些问题;欢迎来改进。使用更多的方法来对抗其他类似漏洞,不只是心脏出血。使用动态和静态分析法来识别在括号里的副标题。
3.1 使用negative测试(动态分析)
negative测试会得到错误的结果。例如,对于一个设置了密码的系统来说,在知道有效的用户名和密码时,要通过很多次的回归测试才能登录成果。negative测试会显示很多无用的用户名和密码,其他的无效的输入会阻止用户登录。
通过negative测试方法创建了一系列的使用错误输入的测试。我指的是每个类型的输入,因为不能测试每一个输入,在动态测试中能得到解释。在回归测试工件中要包含无效数值来测试每一个输入,每个状态/协议转换,每个使用说明书等等。这就会立刻发现心脏出血漏洞,因为心脏出血漏洞包含一个不正确数据的长数值。这也会发现其他类似CVE-2014-1266的错误,如在苹果iOS上使用SSL/TLS会得到的错误。在CVE-2014-1266中,iOS存在接受无效认证的问题。很多的测试中存在有效的认证…但是,没有足够的测试来测试无效的认证。
在大多数情况下只有negative测试对安全还有点用途,之前,我注意到重要的是如何创建测试套件。对于阅读本文来说是明显的,特别是,当我怀疑Eric S. Raymond在讨论测试的优势时使用这些类型的测试。但是这对于软件的开发者来说是明显的,大多数的开发者和组织者都是在使用mostly-positive test套件。很多的开发者很难像攻击者一样的思考,只是错误的通过广泛的测试不可能发现的原因。
通过negative测试的就是起初的半自动的过程,您可以开发出可以执行计算机可处理的规范,并生成大量测试结果的工具…之后看看是否可以控制它。
另一个使用negative测试的重要条件就是是否有一个标准,可能合作开发一个独立的普通测试工件作为FLOSS项目。之后可以通过快速测试所有当前和以后要执行的方法,并且阻止使用者遇到问题。我强烈的推荐使用SSL/TLS协议开发一般目的测试工件;不然会减少效果,这会增加应用的安全性。单独的应用也需要使用附加测试来补充单一测试,但是一般的大测试套件是很有用的。
软件测试是一个完整的领域。存在着不同类型的测试方法和测试范围标准。我只能在本文中总结测试。更一般的信息可以看下Paul Ammann and Jeff Offutt 的Introduction to Software Testing。但是要理解这个:只用使用有效的输入来测试来发现这多的问题,如心脏出血漏洞。
我不知道在整个negative测试中依靠什么,或是其他什么单独的技术,对于安全来说。动态的方法很自然,在真实输入空间只能测试一个微不足道的部分。但是这种方法很容易发现安全漏洞。
3.2 地址核对和标准内存分配在fuzzing
不幸运的是一般的fuzz测试方法在这种情况下是不能很好使用,但是我们可以学习简单的过程。如果可以使fuzzing对一系列的地址进行有效果的、容易的核对和使用。这种类型的工具能侦测到在执行过程中读溢出和加写溢出,并且常常发现其他的存储问题。
许多的工具能够完成对地址的核对;每一种工具都有两面性。但是,如果你没有使用其他的什么工具,我强烈的建议你尝试下address sanitizer。
address sanitizer简单有效;它只是一个在LLVM/clang和gcc中建立的附加的标志。address sanitizer没有什么神奇的;它只是擅长侦测缓冲区的读写溢出问题,释放后使用或是双重释放。它也能侦测到use-after-return和存储泄漏。它不能发现所有的存储问题,但是这是一个很好的工具。它的表现超出平均的73%,使用2x-4x的存储。这种表现一般和测试环境是无关,在侦测这些问题时它很少被提到,在测试过程中Chromium和Firefox网页浏览器都使用的address sanitizer。要了解更多可以去看USENIX 2012或是address sanitizer网页。
还有其他的工具能够侦测内存的使用和分配地址的问题。很多人使用guard pages来检测读和写在缓存。Valgrind被广泛使用和广受欢迎;valgrind在检测内存时能发现很多的问题包括在堆栈中读溢出。另一个广泛使用的工具是electric fence。在运行不同的fuzzer时可以使用不同的工具。
一般情况下,使用fuzz测试时你必须打开你能打开的所有的探测设备。第一个fuzzer侦测时使用这种机制“没有改变的程序崩溃或是死掉?”并且很多的fuzzer还只能做这个。你必须要加强程序的访问,并且要开发尽可能多的访问。你可以增加额外的核对来确保中间和最终程序语句的正确。要不是心脏出血漏洞的出现,你至少应该打开无效的内存访问探测器,如address sanitizer。
许多的工具包括address sanitizer和基于程序的guard page,要求这些程序具有测试正常分配和释放内存的能力。特别是,程序没有必要使用符合分派准测的机制。至少,这个程序应该可以轻松地使用正常分配方法用于fuzz测试。
一个相对的方法是concolic测试,CREST就是一个基于C的concolic测试的自动测试过程工具。但是CREST目前只能用于象征性为线性整数的运算,所以它能在这种情况下工作。更一般的是现在的concolic测试工具不可能发现心脏出血漏洞。如果哪个人说他确认concolic测试发现了心脏出血漏洞,请让我知道。
大家一直都在为fuzzers是否比negative测试复杂而争论不休,但是这只是我的推理。negative测试的一个优点是它很容易入手;假设你已经有了一个测试套件,你就可以开始negative测试。更重要的是negative测试能快速给出一个模糊导致问题的答案,他们要求计算能力很少的开发者使用每一种方法来获得重复测试套件。相反,fuzz测试要求更好的计算能力和对结果的解释;计算能力不算什么,这会影响到对开发者的反馈速度。一个潜在的更快negative测试的反馈能够是开发者更快的实现检测和修复;今天最大的问题就是开发者的时间,而不是计算时间;一个最好的机制能减少开发过程的复杂度。你也可以在某个特定的协议下,使用negative测试套件;你能够在每个测试设备和实施方法中轻松的重新使用测试套件。当然,这不存在什么冲突;最好使用fuzz测试和negative测试两种方法。
3.3 编辑内存分配标准和使用address guard或是sanitizer
如果在对抗来自潜在的漏洞攻击,在未知的环境里你现在就要使用一个程序怎么办呢?
一个方法就是使用侦测在分配的内存的最后区域来实现读的机制,但是使用这种方法你不能改变测试怎么运行;这个观点就是你实际上用的在一个分配要求下的多重分配机制。
存在运行时间侦测漏洞的多种机制;这就是一些例子:
1、Address sanitizer。你要重复调试一个程序时可以使用它。在LLVM/clang和gcc编辑器上Address sanitizer就是一个标志,这相对与C程序的软件简单的多,这占了平均运行的73%,和2x-4x的存储。这不是你想只能手机上做的,很多繁忙的网站不欢迎这些。现在的计算机比过去的有更好的能力和存储,一些环境中就会被接受…这就是你能够立刻对抗未知攻击的可能性。Address sanitizer在侦测一长系列潜在问题上很有作用,包括大量无效的缓冲区访问。Address sanitize不是在所有的编辑器里都无效;这要在其他的如C, C++, 和Objective-C编辑器中来添加它。
2、Intel Memory Protection Extensions。MPX新增了叫边界寄存器的寄存器来控制指针的边界,使用新的指令来运行和使用边界。MPX使用Skylake架构,但是在2014年这些CPU不能和公众见面。这要更长的时间被广泛的得到使用,那不能组成non-Intel系统。
3、内存分配保护页面。一些系统内存分配能够在分配一个用来组织读和写的内存后,添加一个未定的保护页面。这些能否会禁止和阻止心脏出血漏洞,这些取决于它是如何实施的。OpenBSD的malloc的实施支持保护界面。在OpenBSD中,G选项会导致“使用保护页面后的每个页面分配到的数据大小过大,这些会导致访问错误。”这会与P选项进行组合来移动一个页面内的分配。OpenBSD机制可以启动特定的程序,甚至是特定的默认情况下,在整个系统中启动,这样就可以在更多的环境下得到保护。OpenBSD的malloc机制有一个弱点:即使开启G和P两个启动项,少量的分配不会立刻完成保护页面。如果OpenBSD的保护界面机制能够在较少量的分配后立刻插入一个保护页面,我认为会更好,即使这可能会对速度和内存大小有很大的影响。但是即使是这样,开启G和P就意味着所有大于半页的分配会立刻跟随一个保护页面,并且分配一个半页或是更少将会泄漏半页。这就会明显的减少泄漏规模,相比于原来心脏出血漏洞攻击时泄露的64K。内存分配必须要对齐,所以保护页面可能泄漏一些字节的信息,这就取决于如何实施的。我怀疑Address sanitizer要比增加保护页面的分配快,但是添加保护页面不要求更多的程序来进行重新编译,这就是它的优势。不幸运的是GUN的libc中malloc不能有附加的这些功能。
当然,这种方法假设你有一个能启动(1)的内存保护机制和(2)内存保护机制也会在这种机制下工作。很多的机制可以对抗缓存写溢出,不是缓存读溢出,心脏出血漏洞就利用了读溢出。例如:GUN的libc中的malloc()可以选择MALLOC_CHECK_。这就是防止写溢出的方法,但是我不认为它能对抗类似心脏出血的读溢出。同样,Dmalloc’s fence-post检测“在程序从这个区域中读取时不能注意到,只有在写入时才会有通知。”我觉得GUN的libc和一些类似的运行过程中也要增加类似OpenBSD的malloc的保护页面机制,从而对抗读溢出。
这是一个可以减少伤害的方法,而不是一个消除个问题的办法。从安全的角度来看这种方法把缺少保密变成了缺少实用。然而在很多的情况下这是一个很好的协议。一旦受到攻击,这个方法就会使问题变成可视化的,一旦问题可视化后就变的很好改正了。
这个方法很容易和honeypot或honeynet联系在一起。在honeypot或honeynet系统上设置这些硬化的方法。如果攻击者试图破坏软件,这个软件不会崩溃,并且会记录下攻击者的重要日志和追踪记录。Forensics就会侦测到一些专门利用一日0攻击。我认为通过一些日志记录结合入侵侦测系统来进行追踪;在硬化密码库中发生了崩溃,就会特意的记录下。这就会使普遍的侦测利用一日0攻击更加的容易。分布核心基础设施组织和在互联网上其他组织都可以建立这些类保护我们。
虽然这种方法并不能完全解决这个问题,但是他能提供一个有力的缓解功能。一些发行者或组织可能需要在特定情况下使用这些措施,或至少使这些措施变得更容易。
修改代码不会很复杂,并且重新编译也是很简单的。不过,在很多的设备上性能的欠佳都体现的很显著,可能是你失去了硬件后的性能。特别是在使用Address sanitizer时,你会失去一半的速度。因此,我指望使用这种复杂的解决方法,就要考虑到硬件的消耗。在很多的情况下,会影响到运行,在智能手机上就会降低运行速度和电池的寿命,对于当前流行的服务器的话,也会减慢反应速度和增加电量的消耗。如果将来的CPU能支持Address sanitizer,对速度的影响就会显著的降低了。我希望CPU制造商能考虑下这点。
3.4 关注各个领域的手动检测验证
漏洞的代码是人为审查的,显然只有一个人来审查是不行的。
然而,大量的工作就要有专门的人来检查每个领域,为确保得到有效的验证,有时会在计算机安全中得到一个不好的名字。我怀疑的原因之一就是有时候,那些部署清单的人在做什么,之后也不能很好的利用它。但是出色的飞行员经常使用仪表盘,他们知道是做什么的。如果补丁是他们使用清单上工具后的唯一成果,“必须证明每一个不可信的数据字段进行验证,”之后这个漏洞被反击。
列入人为检查/审计的一部分,和一些简单的方法不同。然而,这确实要就检测人能了解所有的补丁,它不能依靠以前的代码来得到帮助。
3.5 对文件包括注解系统的配置源代码的弱点分析
传统的源代码弱点分析是找不到心脏出血漏洞,因为他们使用的是通用的启发式方法,代码复杂,在这种情况下不能很好的起到作用。它总是你能看到的最简洁的代码,但是基于你要完成的任务总是会有一些复杂性,真实情况下人类是不能达到完美的简约。Coverity公司正在开发一些新的,他们认为能够检测到心脏出血漏洞的启发方法…并且对他们是有好处的。至少有一个人已经使用了类似的启发方式。事实上,我希望所有的代码分析工具都能得到改善,从而发现他们以前不能发现的漏洞。但通用的启发方式在某个特定的时间点只能达到这个程度,你能做的更好吗?
回答是肯定的,它叫做为上下文配置的源代码弱点分析工具。基本思想是,你开始使用一个恶源代码弱点分析工具,之后你在提供更多的你要分析的程序的信息。这种方法比仅仅运行源代码弱点分析工具需要更多的时间,而这些额外的信息通常要和一个特定的工具联系在一起。然而,提供你需要的程序的信息,源代码弱点分析工具可以能更好的工作。
Klocwork已经表示这种方法对心脏出血漏洞是很有效的。
现在让我们来谈谈注释系统。在很多的地方来为静态分析工具提供这种额外的信息。一个常用的方法就是对程序添加额外的注释机制,在修改程序时会使用他们。这些注解可能在更改的代码中进行添加,添加在注释中,或是加在单独的文件里。使用C的工具或是注解包括Microsoft’s SAL、splint、Deputy、Oink/CQual++、cqual、和Frama-C ANSI/ISO C。你可以很容易得出添加这些信息确实是一个不同的技术。
认真的使用这些额外的注解来对抗漏洞就要有很大的工作量,如果从现存的代码来说。对于C来说存在许多不同的不兼容的注释系统。对于他们来说是没有什么标准的,这会进一步的阻碍他们的使用。毕竟,它需要添加注释和这些注释会把你锁到一个特定的工具中;Microsoft SAL会有更多的问题,没有FLOSS的应用和这只能在Windows上使用。我认为如果针对每个主要的编程语言包括C在内,任何一种单一被广泛接受的标准注释符号,注释系统将会更加广泛的应用。当没有这么个符号时,像C语言等语言就会很难得到那样一个协议。Peter Gutmann已经写了一些他的经历。
但是,注解系统是由一些好处的,注解系统能够发现简单的漏洞,不用在转变成不同的语言。他们也很少去转变成不同的语言,当然,这并不冲突;你可以切换语言,使用一种新的语言在注释系统中。
3.6 实现100%的分支覆盖率
或许有另一种方法可以发现心脏出血漏洞,实现100%的分支覆盖率。如前面所述,在一个缺失特定程序的中输入有效的验证码时,分支测试是不检测到的。但是分支覆盖可以在不同的实现方法中检测未经验证的分支程序。努力实现一个测试套件,让多个实现全覆盖分支大大增加了丢失了验证码和遗漏了异常处理时被检测到的可能性。更强的测试覆盖措施也会工作的很好,如修改条件/判定语句。
这个测试套件必须要包含多个应用,实现100%的分支覆盖。更重要的是,有不同的实现方式,效果更好。最终,用一个特别的方法来发现漏洞。此外,这种方法比其他的方法更难发现安全漏洞。可能是因为在相同的路径下输入不同的数值,但是只有小部分可以引起问题。如果在测试中其他的一种方法实施了特定的组件和实现了潜在的缺失验证码的代码,它也只能有作用。我从来没有在其他的文献中见过这个特定的方法;人们通常讨论一个执行分支的覆盖。不过,会注意到这种方法不仅可以提高能力,也能发现特殊的漏洞。
实现100%的分支覆盖率比彻底的negative测试更加复杂,这是因为如果你有个很差的测试套件,它会花费大量的时间来从一个错误的分支转向,来弄清楚怎么激发它。错过的分支往往是很难触发的在特定错误的处理系统中,或是对无法验证“不会发生”的分支作防御性设计。此外,这个套件变得更强大能够实现100%的覆盖;很多的组织不能尝试增加一个单一的方法来使分支覆盖到100%,不关心100%的分支覆盖。
这就存在一个问题:这不能很好的反击心脏出血漏洞,因为在很大程度上取决于所有的配置扩展或是注解以及怎么使用。在另一方面,它们不取决于完全冲击的正确输入;静态分析工具可以同时检测大量的问题。
3.7 攻击运行认定
软件开发人员积极的插入和开启运行认定。有人猜测这是对心脏出血的反击,所以我将在这里研究下这中可能性。
软件开发人员可以断言各种价值关系和状态必须是正确的。这些断言可以在运行时停留。几乎所有的语言都会有一种内置的判断机制,有些语言会有一些内置的先进机制的前置条件,后置条件和不变量。在某些情况下,这些语言可以优化一些判句,会留下一些在优化过程中不能优化的问题,一个注解系统可以用静态来实现,一部分可以用动态实现;我先前对注释系统的静态应用的评论。
暂时增强系统逻辑断言是一个更为先进的使用暂时断句的研究方法。你可以在http://www.cl.cam. ac.uk/research/security/ctsrd/tesla/.网站上发现更多的信息。
不用怀疑断句可以有一个极好的机制来用于检测无效状态,无效状态有时是一个最弱的指标。
然而,这中方法在涉及到对抗心脏出血漏洞时确实有些不足。不论是原开发商或是检查的人意识到检查请求报文的长度值是很重要的;因为没有使用长度检查,开发者是不能添加判据来检查它。这是一个在进行negative测试时的问题,但是negative测试可以通过分割这些要开放的功能的代码来简单的实现,很容易证明所有的数据字段都在进行检查,所以我感觉negative测试会更有可能发现存在漏洞的类型。因此,虽然积极的注释可以很有效的对抗漏洞,在某种程度上它会在特定的情况下工作。
我把这种方法看作是一个较为复杂的选择。使用这种方法可以检测到心脏出血漏洞,需要积极使用判据。增加这些判据要使用大量的开发时间和提高运行的成本。
3.8 更安全的语言
心脏出血漏洞产生的原因是C语言不包含有任何的内部检测或是方法来对抗缓冲区不当的限制。不恰当的限制会导致灾难性的问题,所以几乎所有其他的编程语言都会自动对抗不正当的限制。
如果在一个给定的程序中的漏洞可以造成灾难性的影响,那么选择它的程序语言时更应该减少漏洞存在的可能性。越是灾难性的影响,就越要有更好的表现。大多数的程序语言提供对其他危险漏洞的保护措施,如不恰当的限制保护。某些程序语言有更小的可能性出现被误用和不正确使用的结构。理想情况下,一种语言将会阻止所有漏洞。通用的语言都不能阻止所有的漏洞,但是它是编程者争取的一个目标。没有“绝对安全”的程序语言;它是一个继续发展的事物,一些语言提供了更多的对策。
3.8.1 危险语言和为什么使用他们
最广泛使用的与安全有关的软件有C,C + +和Objective-C。所有的这些语言都没有提供缓冲区的访问限制,实际上,它要通过努力来限制缓冲区读和写溢出的出现。对缓冲区访问的不恰当的限制会被广泛使用类型的灾难性的影响漏洞。使用或是转变成其他的语言将会消除缓冲区的漏洞,包括心脏出血漏洞。C语言更是这样,因为它缺乏很多可以避免缓冲区出现问题的高级结构。大多数语言也可以防止内存释放错误,可能会导致安全漏洞,以及一些语言也会被设计成对抗其他漏洞。其中在现在系统中有很多漏洞的原因之一是C、C++、和Objective-C语言的过度使用。实际上,有人提出禁止在安全性敏感的代码中使用这些语言。
C、C++、和Objective-C语言的广泛使用是有原因的。在TIOBE编程区域指数来衡量的编程语言的流行,2014年4月占到了使用人数的前四。这些原因包括更高的性能和界面简单,大型的存储,更好的表现,熟悉性。此外,把语言转变成大型程序是需要很大的努力。让我们来看看原因。
3.8.2 替代产品的运行速度和内存性能
一个经常被引用的问题是使用C,C++,和Objective-C比其他的程序的运行速度快。此外,当要和硬件连接时,其他语言就会缺乏最底层的机制。如果你要很快的速度,你可以直接连接,语言列表中的运行时间会更短。运行速度直接决定着移动设备和服务器领域。基准游戏中速度分析程序是使用不同的语言编写的。“程序语言编程的大致等级”中说到,发送数据和不同语言的包是根据他们的大致速度来实现。没有完美的基准,它始终是一个最好的衡量绩效的具体方法。不过,我更喜欢数字的大致猜测,这个数据即足够代表开始。如果性能是你要追求的,你不想使用汇编语言,可以考虑下下面的分析:
Fortran。Fortran的应用表现经常要比其他的语言好,尤其是在数值计算上。但是,我不清楚很多人会把很多的代码转变成更原始的编程语言。特别是据我所知,即使是现代Fortran也没有和低级的硬件的接口的标准机制。
Ada。Ada用于真实时间系统的应用,因此,它会有更好的性能,包括访问底层的组件。Ada可以用于对抗错误,在编译时表现的最好,它的语法是专门用于对付错误的,Ada一定能对抗缓冲区的心脏出血漏洞。很多人都不喜欢像Ada一样的语言,因为Ada要很严格的静态类型检查,但是这中检查是发现缺陷的关键机制之一。Ada一般广泛的应用在像航空铁路等这些高保障的地方。
ATS。这不是一种众所周知的广泛使用的编程语言,但是它确实非常成功的应用在特定的基准测试套件上。我要指出ATS不在最近使用的程序列表上。
还有很多其他的编程语言,特别当你愿意放弃由基准确定的速度时。例如Go的性能就很好。Rust是另一种你可以考虑的程序语言。Java在当前的JITs上有很合理的表现,一旦它运行起来,但是这有个一个特别的启动时间。其他的语言在基准下也很有用,如Scala,Free Pascal,Lisp SBCL,Haskell, C# on Mono, F# on Mono, and OCaml。不论是D编程语言还是Nimrod语言都列出了相应的标杆。但是使用他们时也要考虑到效率问题。
当然,如果速度不是关键,很多的软件都能被使用。一个研究表明,用.NET, Java, ASP, PHP, Cold Fusion和Perl来编写的程序中的静态漏洞没有统计学上差异。所有这语言要比C,C++或是Objective-C安全。因此所有人都可以防止缓存溢出的问题。
这有太多的编程语言可以使用,我就在这多说了点。我的目的不是列出说所有可以替代的编程语言,而是让人们知道是有替代的存在。
性能不单单是速度,还有内存的管理。在移动设备上尤为重要。C, C++和Objective-C没有自动垃圾收集器,但是其他的语言有这个功能。开发人员如果不考虑内存管理时,他们考虑的是效率,但是在很多的环境下是不现实的。Drew Crawford对移动设备的发展做了很长时间的研究,他指出“如果你需要至少6倍的内存,自动垃圾收集工作会很管用,但是如果这里少于4倍的内存,会减少效率。”iOS基于人工操作的大多数事情的文化,并且试图让编译器做一些简单的东西。Android基于他们努力不在实践中应用垃圾收集器工作,但是不论哪种方式,当他们编写移动应用程序时,每个人都花了很多时间考虑内存管理。内存是不可以替代的。OS X Mountain Lion v10.8中废弃了自动垃圾收集器,在以后的版本中会把它删除。都推荐使用自动引用算法。不是像OS X和iOS一样。这就是人们选择C, C++,和Objective-C的原因。
C, C++, 和 Objective-C编写的程序比其他的语言的运行性能好吗?回答就是语言就被设计成这样。特别是C语言编写的程序能够快速的运行并且使用很少的内存;C语言中指出C的关键是“相信程序员”,“许多操作被定义为如何在目标机器的硬件上使用它”。另外,C的模型是透明的,所以C或是C++开发人员可以使用它,通常评估一个结构。当然,现实会有很大的差距;大量优化的编译器和运行时间要比一般的情况下有更好的性能。
很多的开发者选择C, C++,或是Objective-C来简化其他组件的接口。许多工具都有C的接口,大多数语言的基础设施都可以通过C语言的库。然而,许多其他的编程语言都有C的接口,两种方法为C路径和其他系统通过接口来调用。因此,这并不重要,重要的理由是选择哪种语言。
当使用C, C++,和Objective-C的开发人员使用这些语言时可以减少使用库的危险。最新的C标准还增加了一些安全功能,尤其是那些对字符段的处理。C标准仍然错误的提供易于使用动态调整大小函数的asprintf()或是类似的函数。但是很多现在的系统使用asprintf()。C语言也可以使用GString类型的glib库,strlcpy/strlcat提供,或是其他解决问题中的一个。C++程序可以使用std::string或是它的类似内容。类似,Objective-C具有NSString和NSMutableString类。但是这些设施只能在一定程度上降低风险;即使使用了这些设备犯了错误。
你可以用什么语言来写不安全软件。例如,SQL注入的漏洞是另一个普通弱点,而这可能使用每种语言。然而,大多数语言提供的易于使用,和避免发生问题的机制。我要很小心的使用这个机制…但是对C, Java,和其他语言来说的。
有些语言通常是通过计数器缓冲区溢出,让你暂时停止保护逃逸机制。这些逃逸机制很容易发现和与精心写的代码隔离开来。他们把不安全的隔离成很小的部分,从而降低风险。在很多情况下,你可以重新实现内存缓冲区高速缓存;你可以启动一些漏洞即使缓冲区存在保护时。但是这种重新实现是明显的,在很多的语言中,人们必须要努力避免缓冲区溢出问题。与其相反的是,在C, C++, 和 Objective-C里,你必须做一些附加的工作来避免这种问题。
创建安全软件时,也会遇到一些附加的挑战。我知道没有办法安全的擦除Java里的数据。这是因为Java里没有.NET的SecureString的功能;由于内存分配和垃圾收集器怎么实现多次拷贝,Java的结构是在结束在内存中。这不是Java的特点,很难安全擦除数据在多种语言中。但是Java中,它可以比较容易通过建立一个小的非Java模块来擦除一些数值;该程序的其余部分仍然受到保护不会出现缓冲溢出。此外,利用额外的内存拷贝需要访问大量的程序和运行环境。安全擦除往往是一个有用的减少损伤的措施。相比之下,缓冲区溢出有时候可以直接减少可以利用的连接,有时只要通过网络连接。一般情况下,缓冲区溢出要比大多数其他语言带来的问题更危险。
这很难使用C, C++, 和 Objective-C来编写安全软件。大多数的语言都可以内嵌和防止缓冲区溢出保护…但是C, C++, 和Objective-C例外。另一方面,他们使用这种原因。
开始运行每一个新的安全相关程序,就要仔细的考虑下程序语言。选择一个更安全的语言是很有必要的,这样就可以去除潜在的安全漏洞,其中包括缓冲区溢出的心脏出血漏洞。另外,计算机变得更加强大,在很多情况下可以进行交易一些性能。更重要的是,在开始编写新的程序时,使用另外一种编程语言就几乎变成了零成本。我相信用不太安全的语言时,和重写代码需要花费很多努力。但是,使用几乎任何不是C, C++,或是Objective-C,至少会消除缓冲区溢出和缓冲区溢出漏洞会有很大的影响。
我已经确定了更安全的语言作为一个更复杂的方法,因为切换一个不常用的程序,用不同的语言来实现安全是要花费很多的时间的。
3.8 完全静态分析器
一个完全的静态分析器可以被称为声音静态分析器,用来发现某个特定的漏洞。创建这些类型的工具就是在调整C语言。然而,程序有时不得不限制他们使用的架构,并且开发人员必须提供附加的注解资料。因为这些工具集中发现一切问题,他们往往会报告不存在漏洞,这就必须要分析决定是否真的存在漏洞。但是,如果它应对所有的漏洞,权衡是很有必要的。
3.9 完全认为的核对
一个完全彻底不独立的人为软件检查,主要集中在确保安全性和发现漏洞,这是发现漏洞的最佳方式。这些评论又被称为审核,在展示时,这个软件是很脆弱的。
它的观念是通过人为审核要比通过工具的启发式技术来查找漏洞更直观。更重要是实验数据证实了这一点。例如,Kupsch和Miller发现使用第一原理弱点评估方式的人为审计分析一个示例程序比使用Coverity Prevent和Fortify Source Code Analyzer更全面。人为审核也会出现意外,但是这样的评估会做的相当不错。在Kupsch实验室,FPVA人为检查发现了15个严重的安全漏洞;Fortify发现了6个,Coverity发现了1个,既不是自动化工具发现也不是由人的审查发现。
但是人工核查的缺点也是显而易见的:这需要努力和专业知识来做这样的审核,改变也要审核。人为审查不适合用于所有的软件,甚至当它在面临很复杂的情况时。
请注意,这种审核和以前的可以接受的典型的、简单的回顾是不同的。心脏出血漏洞是试图避免漏洞开发人员发现的,被另一个审核接受。然而,补丁的审核通常是是功能的改善和寻找安全漏洞的过程,所以很容易让他们错过漏洞。正如前面提到的,人为审查每个补丁来要求每个领域的有效认证,要抓住这点…但是现在代码的存在,只是审核新的补丁是不够的。试图在这一点上单独审查每一份文件的补丁可能是不符合成本效应的。此外,补丁的审核可能错过重要问题。一个单独的审核关注整个系统的漏洞是很有效的。
这种审核确实可以发现。事实上,在心脏出血漏洞被发现的同时,TrueCrypt的一个重要组成部分的安全审查发布了。
在很多情况下软件应该进行修改和简化,在审查之前。我认为对于OpenSSL是尤其重要的。那些复杂的程序都很难为工具和人为的评估。OpenSSL使用的复杂结构,这就让它很难被人和机器发现。
3.10格式化方法
但是如果你真的想在某种程度上肯定什么是这个程序要做的?存在着一系列的方法叫做“格式化方法”,这要比上面列出的技术方法更有信心。格式化的方法包括使用“严格的数学技术和工具来规范、设计和验证软件和硬件系统。”由于使用格式化方法是有困难的,他们更可能是在目前的小程序和模块上,是绝对可以使用格式化方法的。此外,如果你真的想要拥有很高的信任程序,格式化的方法仍然是实现这一信心的唯一途径。
这有很多方面可以使用格式化方法。有些人只用格式化的方法来创建规范,不会使用格式化的方法来多做什么。有些人可能会想的多一点,证明有关规范的一些声明或是改进的规范走向更具体的模型。这些方法都不会发现心脏出血漏洞。对于心脏出血漏洞来说,格式化方法要创造关于代码的证明,在源代码和可执行代码水平上,这就是我最关心的。
在关于有关代码注释的系统的实践证明,值得一提的是,注解系统通常可以在各种不同的方式来使用简化的证明。为了了解更多的信息,请参见我有关注释系统的评论。
如果你对更多的感兴趣,特别是支持格式化的FLOSS工具,请参阅从我的类的格式化方法来开发安全的软件。一个有趣的格式化方法工具套件是Toccata,它结合了Frama-C和Why3,以及许多自动化和互助工具。通过组合这些不同的工具来证明程序的正确,在比以前使用更少的努力。更重要的是,他们可以处理C的大量子集;而最正规的方法是不能做到的。SPARK 2014就是基于Ada的,但是可以让你证明相关程序的声明,以及他们最近和Toccata联系在了一起。
正式验证程序的实例中有seL4,CompCert C,cakeML,Tokeneer和iFACTS。
四、前提条件
很多的技术有重要的先决条件;让我们来讨论下。
4.1 在没有特别要求时内存分配
许多静态技术可以对抗心脏出血漏洞的缺陷,包括使用人工核查来对抗,因为OpenSSL的代码很复杂。代码只有简单了才能安全。
许多安全软件开发者首先使用“软件质量”工具来检测特别复杂的结构,然后简化这些结构,这就是安全软件的产生过程。理想的静态分析方法由于代码复杂和变得困难,实用工具来检测这些代码的复杂性,简化他们,在使用静态分析方法就变得很有效。我认为他们是对的,但是我没有发现可以支持他们的数据。因此,这似乎是一个合理的想法,但是我很希望有人最终将创建并发布一些科学研究来支持和反驳这个假设。
在任何情况下,简化的代码是超过运行工具软件的。这是一种心态,应该要有不断的努力来简化代码,不然增加运行能力就会增加软件的复杂性。代码的重构要使它变的更简单和清晰,不是不断的增加新的功能。我们的目标是代码是对的,而不是代码很复杂我们看不出问题。
过于复杂的代码通常会导致安全漏洞。2006年Debian意外事件通过修改软件来消除valgrind警告来打破OpenSSL的随机数生成器。但是,修改软件的人并不真正的了解它。那个人要求帮助,但是OpenSSL的代码复杂就很难使人找到改变后的漏洞。Cox通过研究发生并得到了以下的结论:“尽量不写偷懒的代码,写井井有条的代码。你会不可避免的写一些偷懒没有组织的代码。如果有人问到这这个问题,就把它作为代码不够好的标志。重新把它变得更简单和容易理解。”
LibreSSL的开发者使用了OpenSSL代码和专心用来简化代码。LibreSSL-一个OpenSSL的变版,介绍OpenSSL代码库的一些问题。他们正在做许多的明智的事,如去掉代码支持过时的VAX VMS系统。然而,他们删除了人们关心的代码。例如,他们去除美国政府使用的FIPS 140-2的认证,这同时也受到了许多民营企业的支持。在使代码变得简单和使代码在很多的环境中都有效之间存在着冲突,最简单的代码不能实现什么。很显然,许多程序可以变得比现在简单。
4.2 简化应用程序接口
虽然这稍微的超出了本文的范围,一个相关的问题就是应用程序接口一般情况下都比较复杂。
大多数加密库和数据传输库都是很复杂的,他们通常呈现给开发者一个“困惑矩阵的选项和设置”,因此,大量的应用程序和高层次的库使用不正确的库来进行加密,导致了系统的漏洞。大都数的问题在浏览器中工作中出现,但是他们在其他的代码上仍然是一个问题。想要了解更多的信息,请看“最危险的代码世界:在非浏览器软件中验证SSL证书。”
尽管这在SSL/TLS的使用中是一个技术而不是一个漏洞,但是他们是无关的。加密程序库是创建的复杂接口的一个组件,所以,它仍然是一个故障组件,简化代码。
一个相关问题是底层库和建立在API加密库的系统的很难使用。C忽略了像asprintf和reallocarray等功能。因此,程序员必须要解决这些漏洞,但是他们的解决方法常常会出现bug,这些bug会导致漏洞。
4.3 分配和释放内存
安全的程序必须正常的分配和释放内存,没有特别的分配系统和内存缓存系统。至少,它应该很容易禁用和测试它们来确保禁用了他们的程序。一些技术会减轻心脏出血漏洞的出现,因为OpenSSL的内存分配方式。
基本问题是OpenSSL包括未分配的内存的应用程序特定的缓存空间。目的就是要加快分配在相同数量的重复指令。在默认情况下,OpenSSL正常分配内存,但是在内存区域没有被使用时是不会解除分配的,在很多情况下,把该区域变成未使用的区域变成空闲的,来使它可以立刻重启。这个缓存列表颠覆了一些操作系统和C的运行的一些的机制,因为他们并不是总得到通知在内存不使用时。
Theo de Raadt提到:“几年前我们增加利用措施到libc malloc和mmap,这样一来更多的bugs就会暴露出来。这种存储器会导致死机,甚至是核心的崩溃。分析这些bug,之后永久的维护系统。其他的调试工具也会达到这个目的。在很大的程度上说,这基本就没有性能上的损失。但是在那个时候OpenSSL添加了malloc & free的封装,使库存在缓存中。因为一些平台的性能下降,甚至如果你建立防护技术引入malloc() 和free(),这就无效了。在所有平台上,由于选项是默认的,并且Ted的测试表明你不能关掉它。因为他们没有测试它的年龄。所以后来的bug显示了在该层的内存的泄漏内容。如果内存通过free得到了恰当的返回,这就可能被munmap捕捉到,并激发保护程序的崩溃而不是泄漏你的密码。”
似乎有很多在什么地方出来问题的困惑和OpenSSL的内存分配方法,Chris Rohlf取得了一些有益的验证。我觉得这些验证是很重要的,因为我们必须先用理解这个问题在我们修护它之前。特别是Rohlf指出OpenSSL使用的是标准的malloc() C内存分配方式,当它需要一个全新的内存块时。问题是一旦一个内存块被分配,OpenSSL自身还在自身的管理存储器。Rohlf也指出在很多的环境下是与空闲列表是无关的;一个空闲列表把不同的内存分配在了一起,但是许多典型的内存分配系统也提出了不同的内存分配。然而,Rohlf的典型的内存分配的应用来做同样的事是绝对正确的,关键是OpenSSL的实现阻碍了各种缓解措施。关于OpenSSL的内存分配系统有另一个问题,但是我们首先要介绍下一些基本知识。
一般的方法就是处理一些内存的分配和释放特例,我们的想法就是缓存和重新对某些对象和缓存器在他们没有被使用时,这中方法可以显著的提高性能。这种方法的具体例子包括专门处理共同的内存分配的大小,或是用未使用的高速缓存来重新使用对象和内存器。有一些具体的技术来做这些,包括创建一个对象池和一个slab分配器。Glib库包括一个称为记忆切片的机制,提高内存的分配性能。许多图形用户界面和程序在使用这些方法时,是没有安全感的。
事实证明,一些方法可以不用解决一些检测工具如address sanitizer和使用保护页系统。特别是使用fuzz测试的问题,如果这些工具不被禁用,则fuzz测试就会变得没有效果了。的确,fuzz测试可能不能检测到许多超出范围的读操作,在使用这些方法时。
关于OpenSSL的报告指出OpenSSL的使用是自我管理的一个交大的内存区域的方法然后在进一步细化。这是一个使用slab分配器或是储存器切片时要发生的。使用这个方法就是想要提高性能,在这些情况下使用address sanitizer和保护页系统来抑制检测完全的读溢出。旧的版本称这要发生什么。但是我已经钻研了更多的OpenSSL代码,而这似乎并没有在OpenSSL中的真实性。这对于心脏出血漏洞来说是个好消息。尽管如此,这些类型的分配方案是比较常见的,而且我知道没有人说道这些方法的风险。
安全性软件必须要避免使用内存缓存系统,尤其是那些与一种分配机制联合在一起形成一个分配请求。如果不是这样的话,他们至少提供一个简单的证据机制来禁用它们,并要使用该机制作为其回归测试套件的一部分。OpenSSL有一个禁用机制,但是不再被使用,并且在任何情况下很少有人能了解这种机制,它可以禁用安全分析工具的很多工程。
我们还需要修改我们的教育材料,是开发人员和测试人员都知道内存缓存系统会严重妨碍安全分析。在我的演讲中我已经提出了一些材料来开发安全软件,其他人员也一样需要。
从长远来看,这或许应该是使用C的标准接口在freelists缓存/ slab分配器。如果有标准的接口,你们工具可以很容易的修改和自动调解他们。
4.4 使用标准的FLOSS许可证
这是我的推测,我相信如果OpenSSL使用标准的推广的许可证来进行代码审核会有更多的贡献发生。OpenSSL使用的奇怪的变量许可证是GPL和LGPL。因为GPL是一个最常见的FLOSS许可证。在很多情况下这种不相容性是通过围绕一个许可证漏洞的,或是使用许可证除了在软件中通过使用OpenSSL。不过这个诡异的证书意味着很多人更喜欢GPL或LGPL会情不自禁的禁止或是审核OpenSSL。一些人喜欢限制较少的许可证,这些也有很少的帮助,这不是一个标准的证书。
我确实有一些证据表明非标准证书是一个问题。一个完全独立的软件包GnuTLS在最初是专门创建的。因此使用标准GPL许可证的软件能够轻易的使用SSL/TLS。OpenSSL的LibreSSL转变成了2-clause BSD许可证,当他们写了新的代码,相比与OpenSSL许可证。
在很长的一段时间了,广泛的使用FLOSS证书对FLOSS项目来说是很重要的。1999年Bruce Perens指出:“如果使用这里被列出的一个,就不用写新的许可证了。”后来Open Source Initiative创建了License Proliferation Project,指出许多许可证“和其他开源代码的许可证是不兼容的,严重的限制了开发人员的方法,开发人员仅仅是扩大开源软件的创新方式。”一个重要结果是OSI直接列出了开源代码许可证的页面,只是Popular Licenses,这是“流行,广泛使用,或是强大的社区。”
大多数的FLOSS是基于GPL, LGPL, MIT/X, Revised BSD,BSD 2-Clause或是Apache 2.0 licenses。我建议限制FLOSS程序的许可证列表。你可以添加一些;在OSI的流行许可名单包括更多。然而,这里的问题是OpenSSL许可证根本就不是一个公共无可证。更重要的是它是一个广泛使用的不兼容的许可证的非标准证书。如果可能的话,最好用一般通用的许可证代替。
五、什么会减少心脏出血漏洞的影响?
什么能减少心脏出血漏洞的影响或是完全消除?毕竟当漏洞出现,你想减少影响。下面有一些方法。
5.1 一旦标准内存分配器被替代,启用内存分配器的防御。
许多系统包括减少损坏的内存分配机制,有的有时可以发现问题。这不能对抗问题,但是能够减少影响,例如:
一个常见的方法就是内存在分配和释放时零出,这就意味着如果数据显示,这不太可能是有趣的事。
在2014.4.29,David Wagner提出了一个有趣的选择:“使用一个特定的内存分配器,它能够给每个对象一个随机的地址。在一个64位系统上,会有一个48位的地址空间,这一切都在离分配对象远的地方,这个心脏出血漏洞不会透露任何其他对象的信息。这可以被纳入标准内存分配器。注明:我不主张这么做,我不是说这是最好的防御,我只是回应你的要求想法来阻止它。”
OpenBSD的malloc支持保护页,如前所述。特别是它的G和P选项可以减少和防止信息的泄漏。不幸的是很多的流行malloc不包括这个功能。
5.2 覆盖了你他们一起做的关键信息
关键信息包括密码和私有加密密钥。可以肯定这不是被优化掉的,大多数的编译器将会消除这种覆盖,如果你不能避免的话。
5.3 使用默认的加密方法来做完美的安全
一个加密系统有完善的保密,当它的非确定性生成器生成一个随机的公钥。当PFS启用,当一些密码暴露时,信息不一定会暴露。因为没有用于所有信息没有单一的密码值。
5.4 使用权限分离来达到分离关键密码的作用
它可以帮助从其余的代码中分离加密代码出来,于是即使余下的程序被覆盖,它也不能直接访问私密的密码。
这就会使用到基本的安全原则上,程序要提供最大限度的私密权利对于他们的工作。这些方法可以通过减少漏洞,如密钥等关键信息的软件的数量,从而减少漏洞的数量和影响。不过,我要列出一个减少风险的方法,不是作为一个完整的对错。某个地方的代码必须有提供访问权限的数据,并且这些代码可能有漏洞。这里有些其他的注意事项:
David Wagner指出了这一点,并且进一步解释说:“RSA私钥可能已经被移动到另一个单独的过程,只有运行私有密码代码就会转移到这个过程。在Intel系统中,OpenSSL可以使用采用SGX来运行所有的加密计算在独立的沙盒执行环境下。这被认为是在软件加密模块下的,如虚拟TPM,虚拟HSM等。SGX提供了分离关键代码的硬件支持,但是可以使用其他的机制来代替SGX,像进程隔离或是沙箱。有很多的学术著作上保持这加密代码分离的方法,以及一些考虑到了OpenSSL的特别性。” Rutkowska2013里有关于SGX的介绍,在Brumley里有应用OpenSSL的权限分离的讨论。
Peter Neumann指出在硬件的基础上,沙箱和fine-grained访问控制也会提供强有力的机制来限制权限,从而控制心脏出血漏洞。
一个学生在我的开发安全软件的课上建议内存在服务器上隔离每个用户。这是一个很有趣的想法。
5.5 修复SSL/TLS证书的基础设施,尤其是对证书的吊销。
完整的SSL/TLS的基础设施有很多的问题,包括不值得信任的根证书权限,不良的审核证书和严重损坏的证书吊销过程。作为一个关联点,Qualsys SSL实验室发布了SSL威胁模型。
在目前而言,让我们特别关注证书吊销的过程,在对心脏出血漏洞的回应时,这是被特别的关注的。心脏出血漏洞使人们有可能为攻击者遗漏私密为他们的证书,这是很糟糕的。理论上,漏洞网址可以部署新的证书和撤销旧的证书来解决私密的曝光。不幸的是,今天的证书吊销机制在根本上没有被打破,少数人会很重视这个问题。因此,今天的攻击者往往会导致网页浏览器来接受他们的证书被撤销。有一个迫切的需要推动这方面的工作,远远超过目前可以使用的机制,更好的创造安全标准,并实现它们爱默认情况下无处不在。我认为应该有一个确定推动X509 OCSP的必备,但解决方法会证明这是我们需要的。
这是一个很复杂的区域,我会总结这些问题,这里有几个证书撤销的机制,和使用他们的问题:
证书吊销列表。证书吊销列表是一个吊销证书的大文件。这是最原始的撤销做法。当时的想法是一个程序会下载并检查证书吊销列表在接受证书之前。但是证书吊销列表尚未缩减到今天网络的要求,今天的证书吊销列表是很大的,要频繁的下载更新来保持目前的列表,使他们越来越不和实际。人们已经逐渐远离证书吊销列表,如Firefox 24变成了自动更新证书吊销列表和用户导入证书吊销列表的接口。
在线证书协议。在这个方法中,程序可以与服务器连接来请求特定证书的状态。在线证书协议应该比证书吊销列表需要更少的网络宽度,接近实时的状态检查。然而,在线证书协议创造了巨大的体积和证书发送机构的响应时间要求,因为他们现在必须提供对应所有客户端在一个真实的时间。在线证书协议也要创建了一个严重的隐私问题:它会导致客户透露给CA,它与客户正在联系。另外,不论在线证书协议和证书吊销列表有一个根本性的问题:如果你不能找到答案会出现什么?在实践中,实现线证书协议和证书吊销列表的系统都默认软件连接失败,也就是说,他们接受证书,在他们没有找到其他的东西。但是软故障使得整个方法没有用,因为攻击者往往可以干扰或去掉这些要求。硬故障时可以正常的工作,和其他人说它也可以为他们工作。然而,切换到硬件故障确实有其自身的严重问题。这个附加的检查减慢了到安全网站的连接,并且很多用户对这个额外的时间很敏感。在线证书协议服务器的故障是很常见的,在连接到网络受到制约的地方时你要暂时不用这个,如果硬故障被广泛使用,之后攻击者可以通过短暂的在线证书协议服务器连接来禁止HTTPS。攻击者甚至可以使用在线证书协议封装,包括已经吊销证书的在线证书协议响应,挫败了Langley2014a和Langley2014b的检查。
在线证书协议封装。在线证书协议封装试图通过让证书者来查询在线证书协议服务器,不是最终的用户和得到一个签名的时间的反应,是在有效的时间里解决在线证书协议的问题。当客户端随后访问这个网站时,他们会从该网站获得证书和一个附加的封装时间。如果没有收到封装响应,那么客户端可以回退到另一个方法,如标准的在线证书协议。这不是广泛部署的在线证书协议和证书吊销列表,但是一些网络服务器和网络浏览器都支持在线证书协议装订。然而在线证书协议封装本身仍然容易受到攻击过滤;在很多情况下,攻击者可以去除装订的响应,并阻止客户端获得在线证书协议服务器。在这种情况下,在浏览器中的正常的软失效过程中导致整个系统失效。
证书吊销列表设置。证书吊销列表设置是建立在网络浏览器的短暂的证书吊销列表。例如Chrome浏览器开发人员编译了一天列表,他们认为是“高价值吊销”和使用Chrome的自动更新机制,使这个列表推送到Chrome的安装。Adam Langley,一个谷歌的专家,提倡使用证书吊销列表设置机制,而不是证书吊销列表和在线证书协议。我同意证书吊销列表设置可能是有用的,当一个网络浏览器强行撤销广泛使用的网站证书。但是总体而言,我认为证书吊销列表设置正在从根本上被打破。一个证书吊销列表设置就是一个不完全的黑名单。Langley指出,一个证书吊销列表设置是不完全的,也没有达到足以应付大量的撤销…希望使用证书吊销列表设置,那样我们就能够把撤销的变成重要的和行政的并推动重要的…可悲是,这没有发生。Gibson有一个正确的观点,他指出“互联网证书吊销列表列举出超过两百万撤销和不信任的证书。不过Chrome的证书吊销列表设置目前列出了约24000的吊销证书。两百万中另一种隐式的别Chrome信任。”证书颁发机构安理会已经强烈反对证书吊销列表设置机制作为唯一的证书撤销机制:“心脏出血漏洞是完美典范为什么撤销的是很重要的,即使没有确定的关键妥协。没有人可以肯定的说,他们的服务器的私密被攻击了。大多数撤销正在进行证书吊销列表为“商业原因”,而不是提到证书吊销列表设置。这里很清楚的认为证书吊销列表设置只是一个简单的吊销证书的黑名单。”其他浏览器也有类似的黑名单,而这些可以有效的时间。但是他们不能替代在线证书协议的检查…即使撤销在线证书协议的检查不是100%的准确的。它仍然可以保护用户的比例…关闭撤销检查对每个人来说都是没有保护的。只是要清楚,我不认为证书吊销列表或是在线证书协议运行的良好,我同意证书吊销列表设置可以有一定的效果,尤其是当有一个特定的高调网站证书被曝光。然而,像心脏出血漏洞是不同的,在心脏出血漏洞中,如果他们的私有密钥时网页不能确认被排除了,所以他们需要撤销他们只是确定的…而且由于OpenSSL被广泛的使用,这会硬性到很多的网站。证书吊销列表设置不能解决心脏出血漏洞的问题。
必备的HTTP头文件。Firefox计划实施一个新的必备HTTP头文件,知道像X.509 OCSP等更好的机制必须封装起来便的可用。这只是增加了一个新的HTTP头文件作为一个HTTPS的连接请求的一部分。如果这个新的头文件是有服务器提供的并且支持浏览器,浏览器将会需要一个封装在线证书协议在该域以及子域。再次,如果这是客户端第一次被访问攻击者就可以颠覆这个了,因为攻击者仍然可以伪造初始连接。有些人混淆了用X.509 OCSP主封装HTTP头文件的方法,他们不是一样的。
短暂的证书。一种解决方案是部署只能持续很短时间的证书,如,几天而不是年为单位。从理论上讲这就要在今天工作;到期时间是有效测试证书的基础。不过这可能不是扩展,许多系统假设证书的有效期是很长的时间,并且额外的CA的工作可能很容易犯错误。许多的用户使用过期的证书并且忽略了他们的警告。最后,许多机制可以对抗其他证书的问题通过假设的证书很少的改变,所以这些修复能够增加漏洞。
X.509 OCSP 必备的封装。在这种方法中,该证书具有一个标记,表示该用户端必须要接接OCSP封装,然后OCSP封装被广泛使用。这是一个附加的OCSP封装,但是它可以防止攻击者筛选OCSP封装,因为客户知道什么是错误的。请注意这不只是封装OCSP,这不是一个必要的封装HTTP头文件,人们有时会混淆这些不同的方法。不像必须封装的HTTP头文件的方法,攻击者无法轻易筛选出这一点,因为证书本身指出需要封装。这中方法对短寿命的证书同样有效果,就不会有这些问题。Langley, CASC和其他的公司都推荐使用OCSP必备封装。然而虽然有必须的封装,这没有正式的规范并且这种扩展不被广泛使用。对于这个工作我们需要一个正式的规范,在服务器和浏览器中广泛的使用包括扩展的X.509证书包。
其他方法。还有其他的方法,尽量处理犯罪嫌疑人的证书,包括TACK和Mutually Endorsing CA结构。再次这些没有被广泛的使用和接受。
5.6 使软件容易更新
问题将会发生,组织者必须在必要的时候修复他们。如旧的Android 4.1.4就容易受到心脏出血漏洞的攻击。这是因为Google虽然很快的修复了这个版本,但是手机的制造商很慢的更新手机,手机运行商通常会推迟更新的时间。也到了谈论制造商和运营商不能修复手机的问题,当有安全漏洞要修复时,运行商已经即时的出售了手机。同样,我认为通过FIPS 140-2验证过程需要改变,以便库中的漏洞被发现和更新。
5.7 存储散列的密码
当然,继续把散列的数值作为密码,而不是明文或是可逆值,如果要存储密码为明文或是可逆的值,你没有说服人的理由,你就不能使用。
5.8 一般问题:安全软件教育/培训和减少攻击者的攻击
我要提到各方面的改善可能会减少一般可利用的漏洞的数量,有时利用这些。这就包括安全软件教育/培训并且要减少攻击者的攻击。
很多的软件开发人员依然没有受过什么教育和培训来开发软件。然而,几乎所有的软件可以直接连接到网络上,或是可以通过一个网络接收数据。许多开发人员不知道如何设计软件来对抗攻击,一般的漏洞是什么,和如何正确的对抗。事实上,很多开发人员不知道安全软件和软件安全的区别。这些材料是可用的,我在一本书上写了如何开发安全软件,开发人员必须要学习和运用这些知识。
我们也需要减少经济效益的攻击,经济激励会使人们发现漏洞并要出售给攻击者。在很多情况下人们不会把漏洞告诉防御者,他们可以通过出售这些漏洞给攻击者来得到很多的钱。毕竟人们可以通过出售一个单一的漏洞来合理的挣到100万。赏金根本跟不上当时的情形,我们需要探讨如何减少这些诱惑。例如也许我们应该把漏洞信息卖给不是供应商和政府的人定罪。基本上对于漏洞信息的捐献:有意的消除经济引诱在一个特定的区域来获得一个更好的社会。我认为这不可能防止公民来告诉他的国家软件的漏洞;公民必须把这作为他们的职责。我觉得没有一个政府会禁止购买这些信息。但是额外的限制可能会减少人们积极寻找漏洞,不是修复而是利用他们。显然有一些人会做违法的事,但是有些人会避免做违法的事,这是因为他们怕被捉到。你并不需要停止所有可能,只是改变。也许有更好的办法,如果有的话,请提前说,在任何情况下,我们需要找到一个方法来做物质的工作和不是安全。
六、应用这些方法
正如我前面提到的,开发安全软件需要的工具和方法的结合。当有错误时,要弄清楚发生了什么,我们需要了解它们失败的原因,并要试图做的更好。
这不是一个很好的时机来使用加密库。这些库是很重要的,但是最近发现了很多的问题:
1、本文的重点是OpenSSL中的心脏出血漏洞。
2、苹果的iOS遇到了漏洞,这是一个简单的故障来检查无效的证书。这些漏洞可能已经通过各种机制,包括静态死代码检测器,测试覆盖工具,或是无效认证的否定测试。
3、GnuTLS也不能正确的认证证书,其次,似乎有可能检测到这个在代码公布之前,其中包括否定测试。
4、OpenSSL CCS的注入。其中一些精心制作的可能会导致密钥的成为弱项。Masashi Kikuchi已经分别描述了他是怎么发现这个漏洞的。他首先想到了使用Coq来证明使用的正确性。他专注于过度的CCS,然后检查如何验证代码转变条件。他发现OpenSSL不能验证失败的情况,并且发现了漏洞。
5、一个随机数生成器不能在OpenSSL运行,值得注意的是,可以通过它来检查这个错误,所有的基本工程测试已经掌握了这一点。
许多人依靠加密库但是评估这些要有专业的知识,美国政府已经建立了一套流程来评估加密模块,称为FIPS 140-2。我认为这是个好方法来广阔的评价这些很重要并且难评估的项目。
这有更重要的事情,虽然符合FIPS 140-2进程,但是不检查加密协议,包括SSL/TLS的实现。相反,当前的FIPS 140-2进程只能计算它在密码库内的算法和检测在密码模块内的方案。我没有说清楚这个旧版本的文本,我希望弄清这些事。作为实施指南的FIPS PUB 140-2和加密模块验证程序的有效性。“该加密模块可以实现在安防行业已知的各种协议。这些协议的例子是IKE, TLS, SSH, SRTP, SNMP和TPM,在NIST SP 800-135rev1列出来。FIPS 140-2以及其附件没有解决方案,只有在加密算法和方案被认可和允许时,这些在操作模式下使用。”
实际上,OpenSSL坚持使用FIPS 140-2认证,它修复了心脏出血漏洞由于使用了附加的技术。FIPS 140-2进程不能评估正常的OpenSSL代码,只是评估了叫OpenSSL FIPS对象模块的特别的软件模块。OpenSSL FIPS对象模块有一样的接口,并且从OpenSSL代码中衍生出来,但它还是一个单独的模块。开启“FIPS模式”来结束FIPS模块代码,而不是使用常规的OpenSSL代码来实现加密。因此OpenSSL FIPS对象模块可以保持其通过FIPS 140-2的认证,即修复心脏出血漏洞,这是因为FIPS 140-2进程不评估SSL/TLS协议,因为不符合FIPS某块的代码必须要修改。在其他方面不同的情况下发生的。通常情况下,任何的加密模块的改变都不能导致验证的损失,这就需要很长的时间和金钱来得到一个新的验证。亏损的危险就是一个反常的激励:加密模块的开发人员有一个强烈的动机来区分问题。如果这是正确的,我可以肯定OpenSSL开发人员和FIPS的使用者和高兴。这就意味着心脏出血漏洞能够很快的得到修复在符合FIPS时,我确认在2014-05-09理解NIST。
因此通过设计FIPS 140-2进程中没有通过SSL/TLS来实现的包括加密协议在内,我觉得这公平来询问,但是,如果要注意保密协议。正确的评估加密协议需要相同类型的专业知识和其他的加密代码。很容易创建和运行一个大的测试套件来对抗如SSL/TLS的标准协议。这并不奇怪,验证过程没有发现随机数生成器的失败。我想通过FIPS 140-2进程至少是使用动态测试每一个支持加密随机数的生产器,从而确保他们是随机的,并且可以避免常见的错误。这将不花费很多和提供了一些信心,如果FIPS 140-2进程不能延长审查加密协议,那么事情应该建立来审查这些。一般情况下,我们需要重新测试FIPS 140-2来使它运行的更快更彻底。当前的进程使它很难更新库,如让一个人得到了关于安全和兼容性的结论。
没有测试过程中可以找到所有的问题,所以期待的完美是不合理的。不过,存在这新的技术来评估保密代码,这就会增加速度减少成本。更重要的是,我们都需要对攻击者的学习来增进当前评估过程来对抗容易忽略的漏洞。我的目标不是来毁掉现有的各种评估进程,评估是一项很难的任务。我的目标是要弄清楚做什么可以改善这些事情,因为加密是最重要的。
需要更严格和透明的程序来测试加密协议,一个要求对安全漏洞进行更新和公开的更新程序来防止复发。我能够很容易的看到FLOSS项目来创建一个更严格的测试套件,指的是通过密码库的使用和用户的关注程度。
我想我应该提一下FLOSS。有些人曾经试图宣称心脏出血漏洞在一个FLOSS不能创建好软件的证据。这没有意义,在专有软件中也发现了漏洞,在2013年,Coverity的扫描报告中发现“开源代码的质量优于专有的C/C++项目。”在现实中一些FLOSS程序是安全的,但是专有软件就不是很安全了。FLOSS有些潜在的安全优点,但是他们只是潜在的,你必须要检测特定的软件来确定它是否适合您的需要,包括它的安全性。
Eric S. Raymond把下面这叫做“Linus’ Law”:“使用一个足够大的β测试和联合的开发基础,几乎所有的问题很快的成型和修复就变得很明显了。”或是不正规的“只要你认真的寻找就会发现漏洞。”但是,这不意味着一些人想要。首先Raymond截然不同的发展FLOSS;他不是在谈论FLOSS和非FLOSS。其次,注意到更小心的措施需要“足够多的联合开发人员”基础;加密学使得得到一个大的开发者基础成为问题,并且非标准的OpenSSL证书有可能抑制了合作开发人员的数量。第三,注意这些文字“几乎每个问题都会很快的形成”,他从来没有声称发现了所有了问题,或是他们很快的被发现。最后,文中指出事实证明传统的方法在发现和对抗这些问题时不会奏效,虽然有很多的工具和方法来分析OpenSSL。相反,系统问题来发现类似的漏洞,因为不同的人使用类似的假设。好的消息是我们可以找到漏洞并且修复这些漏洞,因为漏洞的成因是公开讨论的。在大的设置中,本文代表了人们识别系统的问题来修复他们,从而类似的漏洞会很快的发现和修复。
本文着重关注如何应对技术。然而这里还有很多的非技术问题。Summer Maynard的“什么能让心脏出血可以教导OSS社区的市场营销”,这就展示了心脏出血是怎么被推销的。市场营销是很重要的;心脏出血是一个很糟糕的漏洞,好的营销加快的反应速度和降低了伤害。项目可以帮助关键的部件,这些有潜在问题的;核心的设施要数百万的美元来资助开源项目,这个项目是核心计算机功能的关键路径,这收心脏出血漏洞启发的。
七、范例
那么是不是有做的很好的例子?毕竟容易引起抱怨,但是如果没有人可以做的很好,那么这应该是不可能的。此外,如果没有可以复制的例子,就很难学习怎么做了。
我要求人们在可靠性和安全性方面来区分强大的FLOSS例子。当然,一个程序会有一个强劲的投入和不安全性。此外,即时是好的系统也偶尔会有问题的。这是一个很好的想法来看这些例子,因为很容易使用类似的方法在你在实际运行中。这有一些人们确定的项目:
OpenBSD。OpenBSD渴望成为安全领域的第1。他们由一个6-12人的队伍来进行安全审计:“我们不能找到很多的安全漏洞,因为我们正在找软件的基本问题,使用很长时间后人们才会发现安全问题,之后修复这些问题。在系统的任何领域都会发现漏洞。在我们审计中发现了在安全问题中新的类,而且往往这些较早审核的源代码需要重新设计时要考虑到这些漏洞。代码要经过多次的审核,并且由很多人使用不同的方法来审核,另一个安全的审核过程就是他们的积极性。在很多的条件下,我们发现对于开发的决心不是一个问题。在我们的审计过程中,我们发现了很多的问题,并且我们努力解决这些问题,即时没有得到证实。” 他们试图创建并实施对抗这些漏洞的新方法,包括strlcpy()/strlcat(),保护页面,和随机malloc()。他们还在“默认安全”下工作,同时进行全面的披露。
OpenSSH。OpenSSH是实现SSH协议和密钥连接的工具。OpenSSH是在OpenBSD项目的两个团队开发的。一个团队做基于OpenBSD的开发,其他的团队需要运行这个版本在许多操作系统上运行。OpenSSH使用的是OpenBSD的安全开发流程。OpenSSH的开发人员一直在努力降低OpenSSH被攻击的可能性。他们的方法有防御性程序,使用独立的库来减少复杂性,轻度的改变协议来减少攻击,特权分离,通过改变程序来最大化的缓解在操作系统的攻击。想要了解更多的OpenSSH的权限分离可以查阅Provos2003。
SQLite。SQLite是通过使用非常积极的测试方法来获得可靠性。该项目的代码行中超过了1000的测试代码和测试脚本。他们的作为包括三个独立开发的测试工具,异常测试,fuzz测试,回归测试,自动资源泄露测试,100%分支测试和MC/DC覆盖测试,数以百万的测试方案,广泛的使用assert()和运行时间检查,Valgrind分析,整数溢出检查,开发者清单。他们没有编译警告,在警告开启或是使用Clang静态分析工具。在2014.5.10,Peter Gutmann告诉我:“我一直使用SQLite完成我专业级软件开发,我谈论了怎么开发和测试它,在受到强烈的影响下。”
Postfix。我注意到Elaine R. Palmer和Bill Cheswick认为他们对安全和可靠性都全面的了解。Postfix的方法来开发安全软件重点在于存在一个非常有经验的团队,从头开始编写到安全,涉及到一组守护进程分别执行不同任务的集体结构。Postfix使用C和POSIX的安全子集,并结合创建安全的替代品的一个抽象层。例如,它有一个“vstring”创始人的帮助来缓解缓冲区溢出的攻击和“safe open”创始人来阻止竞赛条件。
GPSD。全球定位系统服务守护进程。这使用了大量的回归测试,使用多个工具的严格的静态测试和可以减少风险的构架方式。他们使用一个自定义的框架来拓展回归测试套件,包括使用诸如valgrind工具。他们的静态分析工具包括splint,cppcheck和Coverity;他们说道:“我们不知道没有比GPSD更强大的套件,包括全部的splint注解,并强烈怀疑没有存在。”或许更重要的是,他们的设计没有缺陷。Eric Raymond说到,“如果移动或是主机不是Windows,GPSD肯定可以运行,在世界上所有的智能手机的GPS监控,DARPA挑战一个重要的航海系统,从无人驾驶汽车开始,还有大多数的无人机和机器人,只有CVE和在十年内没有任何的漏洞。在几个月的时间内没有任何的缺陷报告,GPSD是使用传统C的基础,从而可以使你非常接近不用判断。我得到了疯狂的回归测试和常规的四个静态分析器。”
这当然不是一个完整的清单,他们中的漏洞会被发现的。尽管如此,它指向用来提高安全性和可靠性的项目,以及他们是如何工作的,让别人找到什么值得模仿。
八、结论和建议
有几种方法可以发现心脏出血漏洞,在这漏洞软件发布之前。这不是一个真对OpenSSL开发人员的,他们在一直的努力减少漏洞的数量,包括审计的人数和工具。相反,本文是来帮助改善的,OpenSSL和其他的项目可以通过改变他们如何开发和评估软件来阻止将来类似的漏洞发生。
我们已经学了一个重要的事情是许多的静态和动态分析方法使用在分析的项目中,也没有找到心脏出血漏洞。这就包括使用自动测试套件,fuzz测试方法,和典型的语句或是分支代码覆盖率的方法。几个源代码的弱点分析仪的开发人员正在改善他们的工具来检测非常类似心脏出血漏洞。我认为我们应该继续使用这些工具,但是和明显不够。想要打造安全软件项目还需要添加一下的一种方法:
1 彻底的negative测试(动态分析)
2 带地址检测和标准内存分配的fuzz(动态分析)
3 在标准内存分配器下编译和使用地址保护或是sanitizer(复合分析)
4 在各个领域内有验证是使用手动检测(静态分析)
5 上下文配置的源代码弱点分析仪,包括注释系统(静态分析)
6 100%分支覆盖率(复合分析)
7 入侵时间描述(动态分析)
8 更安全的语言(静态分析)
9 完全静态分析器(静态分析)
10 彻底的人工核实和检测(静态分析)
11 格式化方法(静态分析)
项目应该保证容易分析。例如简化代码,正常分配和释放内存,使用标准的FLOSS许可证书,这要具有广泛的兼容性。这将会是很好的使用一个编程语言,包括C,有被广泛接受的标准注释符号,从而使注释语言更容易被接受。象C语言是很难得到这样的协议的,但是我觉得要是能够使它标准化,他们就会更广泛的使用。
还有很多的方法可以减少心脏出血漏洞的影响:
1 一旦标准的内存分配器被取代,开启内存分配器的防御。在很多系统如Linux上的GNU malloc就没有这种机制,我们要首先进行添加。
2 覆盖关键信息在处理他们时。
3 使用完美的缺省的向前安全性的加密算法。
4 使用权限分离的临界加密用于其它的代码部分。
5 修复SSL/TLS的证书架构,尤其是默认证书的吊销过程。这就要协调一致的努力才能得到真正的解决方案中的规定,实施和部署;我们要从现在开始。
6 是软件升级变得简单。
7 零散的储存密码
8 一般的问题:安全软件培训和教育,降低攻击动机。
教学材料的改进和添加,特别是我们需要警告开发人员在内存缓存系统中的潜在的安全问题,在使用C,C++, 或是Objective-C;现在经常用的。当然真是的问题是开发人员学习使用安全软件,尽管几乎所有的程序都在受到攻击。
现在让我们来谈谈SSL/TLS的实现。在短时间内,我认为FLOSS项目的建立是建立在一个全面的SSL/TLS回归测试套件,使用以下的技术:
该套件要使用彻底的negative测试,它当然要有测试选项。
这将会是最好的,如果这个测试套件使用了很长的时间可以达到100%的分支覆盖,以为测试使用了多个实现方法,可以帮助检测缺失的错误输入和错误处理。
使用带地址检测和标准内存分配器的fuzz和传统的negative测试结合的方法会更好,fuzz测试可以发现许多的安全漏洞,但是传统的fuzz测试就很肤浅,并且测试效果有限,如果他们自然的应用密码协议。结合了fuzz测试和传统测试可以取得更大的进步,在协议上可以做到比单纯的fuzz测试更有效的测试。一个完全的测试工具应该可以测试到细微的错误状态。
像这样的测试套件可用多种实现方式协议来实现,但是我认为要使用SSL/TLS开始。最近,在很多的SSL/TLS的运行中发现了很多的漏洞,所有这些都可以通过negative测试来实现。如果任何加密库有漏洞,在其他保护下可以泄露数据。这个测试套件可以重启所有的SSL/TLS项目,在任何一个开发人员做出任何的改变,在他们在用户的电脑上显示很长时间以前消除他们。这个套件可以用于潜在的用户和政府,如果使用验证,可以提高供应商额外的测试来添加下一个版本。一个常见的测试套件将使我们更有信心在所有的SSL/TLS中,在开始点这些测试套件会很有用,在开始的地方便的很容易。它还有资金的优势;如果你不知道你是否支持OpenSSL,LibreSSL叉,或是其他的,这不重要-这个套件可以帮助大家。个别的项目要继续使用自己的测试套件,但是显然现在的测试套件是不够的。这也可以扩展到其他的加密协议,依赖一中技术来测试漏洞是不坏注意,包括创建一个共同的严格测试套件;我们要更多的套件才行。但是这可以说是一个好的开始。
更广泛的说,项目需要检查心脏出血的漏洞以及其他的漏洞,并且要确定他们是有效的。他们也需要检查一个项目,在这个项目做的很好时,来看使用寿命方法来复制。
这没有更好的办法。然而,这需要更重要的课程学习,要积极的使用套件才能是类似心脏出血漏洞不再发生。
九、参考文献
当前的URLs是2014.5.28。我已经把文本改成了规定的格式了,人们可以在打印版上发现重要的参考文献了。
[Ammann2008] Ammann, Paul and Jeff Offutt. Introduction to Software Testing. 2008. University Press. ISBN-13: 978-0521880381. ISBN-10: 0521880386. http://cs.gmu.edu/~offutt/softwaretest/
[Anderson2014] Anderson, Paul. Finding Heartbleed with CodeSonar. May 1, 2014. http://www.grammatech.com/blog/finding-heartbleed-with-codesonar
[Appel2014] Appel, Andrew W. Verification of a Cryptographic Primitive: SHA-256 http://www.cs.princeton.edu/~appel/papers/verif-sha.pdf
[Apple2013] Apple. Apple Automatic Reference Counting (ARC). “Transitioning to ARC Release Notes.” August 2013. https://developer.apple.com/library/mac/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html
[ArcaneSentiment2014] Arcane Sentiment. A sound bug finder is an unsound correctness prover. 2014. http://arcanesentiment.blogspot.se/2014/04/a-sound-bug-finder-is-unsound.html
[BAH2009] Booz Allen Hamilton. Software Security Assessment Tools Review. March 2, 2009. http://samate.nist.gov/docs/NAVSEA-Tools-Paper-2009-03-02.pdf
[BenchmarksGame] Benchmarks Game. http://benchmarksgame.alioth.debian.org/u32/which-programs-are-fastest.php
[Bessey2010] Bessey, Al, Ken Block, Ben Chelf, Andy Chou, Bryan Fulton, Seth Hallem, Charles Henri-Gros, Asya Kamsky, Scott McPeak, and Dawson Engler. A Few Billion Lines of Code Later: Using Static Analysis to Find Bugs in the Real World. Communications of the ACM, Vol. 53 No. 2, Pages 66-75. 2010. http://cacm.acm.org/magazines/2010/2/69354-a-few-billion-lines-of-code-later/fulltext
[Brumley] Brumley, David and Dawn Song. Privtrans: Automatically Partitioning Programs for Privilege Separation. http://users.ece.cmu.edu/~dawnsong/papers/privtrans.pdf
[Butler] Butler, Ricky W. “What is Formal Methods?” http://shemesh.larc.nasa.gov/fm/fm-what.html
[Cassidy2014] Cassidy, Sean. Diagnosis of the OpenSSL Heartbleed Bug. 2014-04-07. http://blog.existentialize.com/diagnosis-of-the-openssl-heartbleed-bug.html
[CASC2014]. Certificate Authority Security Council (CASC). CASC Heartbleed Response. 2014-05-08. https://casecurity.org/2014/05/08/casc-heartbleed-response/
[Chou2014] Chou, Andy. “On Detecting Heartbleed with Static Analysis”. April 13, 2014. http://security.coverity.com/blog/2014/Apr/on-detecting-heartbleed-with-static-analysis.html
[Coverity2014] Coverity. 2013 Coverity Scan Report. 2014. http://softwareintegrity.coverity.com/register-for-scan-report-2013.html?cs=pr
[Cox2008] Cox, Russ. Lessons from the Debian/OpenSSL Fiasco. May 21, 2008. http://research.swtch.com/openssl
[Crawford2013]. Crawford, Drew. “Why mobile web apps are slow.” July 2013. http://sealedabstract.com/rants/why-mobile-web-apps-are-slow/
[de Raadt] de Raadt, Theo. “Re: FYA: http://heartbleed.com/”. Newsgroup gmane.os.openbsd.misc. http://article.gmane.org/gmane.os.openbsd.misc/211963
[Georgiev2012]. Georgiev, Martin, Subodh Iyengar, Suman Jana, Rishita Anubhai, Dan Boneh, and Vitaly Shmatikov. “The most dangerous code in the world: validating SSL certificates in non-browser software”. ACM Conference on Computer and Communications Security. 2012. pp. 38-49.
[Gibson] Gibson, Steve. An Evaluation of the Effectiveness of Chrome’s CRLSets. 2014. https://www.grc.com/revocation/crlsets.htm
[Goodin2014a] Goodin, Dan. March 4, 2014. “Critical crypto bug leaves Linux, hundreds of apps open to eavesdropping”. Ars Technica. http://arstechnica.com/security/2014/03/critical-crypto-bug-leaves-linux-hundreds-of-apps-open-to-eavesdropping
[Goodin2014b]. Goodin, Dan. “How Heartbleed transformed HTTPS security into the stuff of absurdist theater: Certificate revocation checking in browsers is “useless,” crypto guru warns.” Ars Technica. 2014-04-21. http://arstechnica.com/security/2014/04/how-heartbleed-transformed-https-security-into-the-stuff-of-absurdist-theater/
[GNU-Licenses] GNU project. Various Licenses and Comments about Them. https://www.gnu.org/licenses/license-list.html#OpenSSL
[Goodin2011] Goodin, Dan. “How is SSL hopelessly broken? Let us count the ways: Blunders expose huge cracks in net’s trust foundation” The Register. 2011-04-11. http://www.theregister.co.uk/2011/04/11/state_of_ssl_analysis/
[Gutmann] Gutmann, Peter. Experiences with SAL/PREfast https://www.cs.auckland.ac.nz/~pgut001/pubs/sal.html
[Hatton2003]. Hatton, Les. “EC–, a measurement based safer subset of ISO C suitable for embedded system development.” 2003. Information and Software Technology, 47 (3) (2005), p. 181-187. http://www.leshatton.org/index_SA.html
[Hatton2005] Hatton, Les. Language subsetting in an industrial context: a comparison of MISRA C 1998 and MISRA C 2004. November 20, 2005. Information and Software Technology 49 (5), p. 475-482, May 2007. http://www.leshatton.org/index_SA.html
[Heartbleed.com] Heartbleed.com web site.
[Hofer2010] Hofer, Thomas. Evaluating Static Source Code Analysis Tools 2010. http://infoscience.epfl.ch/record/153107/files/ESSCAT-report
[Hsu2008] Hsu, Yating, Guoqiang Shu, and David Lee. “A Model-based Approach to Security Flaw Detection of Network Protocol Implementations” http://www.ieee-icnp.org/2008/papers/Index12.pdf
[Jplus2014] Jplus. 2014. Approximate speed classes of programming languages. XKCD Forums. http://forums.xkcd.com/viewtopic.php?f=11&t=108685
[Junestam2014] Junestam, Andreas and Nicolas Guigo (iSECpartners). Open Crypto Audit Project: TrueCrypt: Security Assessment. Prepared for the Open Crypto Audit Project. 2014. https://opencryptoaudit.org/reports
[Kupsch2009] Kupsch, J. A. and Barton P. Miller. “Manual vs. automated vulnerability assessment: A case study”. The First International Workshop on Managing Insider Security Threats, West Lafayette. 2009. http://research.cs.wisc.edu/mist/papers/ManVsAutoVulnAssessment.pdf
[Kupsch2014-April] Kupsch, James A., and Barton P. Miller. “Why do Software Assurance Tools Have Problems Finding Bugs Like Heartbleed?” https://continuousassurance.org/swamp/SWAMP-Heartbleed-White-aper-22Apr2014.pdf
[Kupsch2014-May] Kupsch, James A., and Barton P. Miller. “Why do Software Assurance Tools Have Problems Finding Bugs Like Heartbleed?” https://continuousassurance.org/swamp/SWAMP-Heartbleed.pdf
[Langley2014a] Langley, Adam. No, don’t enable revocation checking. 2014-04-19. https://www.imperialviolet.org/2014/04/19/revchecking.html
[Langley2014b] Langley, Adam. Revocation still doesn’t work. 2014-04-29. https://www.imperialviolet.org/2014/04/29/revocationagain.html
[McLoughlin2004] Mark McLoughlin, Mark. June 22, 2004. https://people.gnome.org/~markmc/openssl-and-the-gpl.html
[Miller2005] Miller, Damien. “Secure Portability”. AUUG 2005. October 2005. http://www.openbsd.org/papers/portability.pdf or http://www.mindrot.org/~djm/auug2005/
[Miller2007] Miller, Damien. “Security measures in OpenSSH”. Proceedings of the AsiaBSDCon 2007, Usenix. March 2007. http://www.openbsd.org/papers/openssh-measures-asiabsdcon2007.pdf
[NIST] NIST (SAMATE project). Tool Survey. http://samate.nist.gov/index.php/Tool_Survey.html
[NIST-Sound] NIST. NIST SAMATE SATE V Ockham Sound Analysis Criteria. http://samate.nist.gov/SATE5OckhamCriteria.html
[Perens1999] Perens, Bruce. “The Open Source Definition” Open Sources: Voices from the Open Source Revolution 1st Edition. January 1999. 1-56592-582-3. http://oreilly.com/catalog/opensources/book/perens.html
[Provos2003] Provos, Niels, Markus Friedl, and Peter Honeyman. “Preventing privilege escalation”. Proceedings of the 12th USENIX Security Symposium. Pages 231-242. August 2003. https://www.usenix.org/events/sec03/tech/full_papers/provos_et_al/provos_et_al.pdf
[Raymond1999] Raymond, Eric. “The Cathedral and the Bazaar”. The Cathedral and the Bazaar. http://www.catb.org/esr/writings/cathedral-bazaar/ – note that Linus’ law is at http://www.catb.org/esr/writings/cathedral-bazaar/cathedral-bazaar/ar01s04.html
[Ritter2014] Ritter, Tom. iSEC Completes TrueCrypt Audit: Is TrueCrypt Audited Yet? Yes, in part! April 24, 2014. https://isecpartners.github.io/news/2014/04/14/iSEC-Completes-Truecrypt-Audit.html
[Rohlf2014] Rohlf, Chris. 2014-04-11. My heart is ok, but my eyes are bleeding. Leaf Security Research. http://blog.leafsr.com/2014/04/11/my-heart-is-ok-but-my-eyes-are-bleeding/
[Ruef2014] Ruef, Andrew. Using Static Analysis And Clang To Find Heartbleed. April 27, 2014. http://blog.trailofbits.com/2014/04/27/using-static-analysis-and-clang-to-find-heartbleed/
[Rutkowska2013] Rutkowska, Joanna. Thoughts on Intel’s upcoming Software Guard Extensions (Part 1). August 30, 2013. http://theinvisiblethings.blogspot.com/2013/08/thoughts-on-intels-upcoming-software.html
[Sarkar2014] Sarkar, Roy. “Saving you from Heartbleed”. April 16, 2014. http://www.klocwork.com/blog/software-security/saving-you-from-heartbleed/
[Schieferdecker2012] Schieferdecker, Ina, Jürgen Gro?mann, and Martin Schneider. Model-Based Fuzzing for Security Testing. 2012-04-21. http://www.spacios.eu/sectest2012/pdfs/SecTestICST_Schieferdecker.pdf
[Serebryany2012] Serebryany, Konstantin, Derek Bruening, Alexander Potapenko, and Dmitry Vyukov. “Address Sanitizer: A Fast Address Sanity Checker”. USENIX ATC 2012. https://www.usenix.org/system/files/conference/atc12/atc12-final39.pdf
[Shahriar2008] Shahriar, Hossain. Mutation-based testing of buffer overflows, SQL injections, and format string bugs. 2008. http://qspace.library.queensu.ca/handle/1974/1359
[Spinellis2012] Spinellis, Diomidis, Vassilios Karakoidas, and Panagiotis Louridas. “Comparative language fuzz testing: Programming languages vs. fat fingers.” PLATEAU 2012: 4th Annual International Workshop on Evaluation and Usability of Programming Languages and Tools – Systems, Programming, Languages and Applications: Software for Humanity (SPLASH 2012). ACM, October 2012. (doi:10.1145/2414721.2414727) http://www.dmst.aueb.gr/dds/pubs/conf/2012-PLATEAU-Fuzzer/pub/html/fuzzer.html
[Sutton2007] Sutton, Michael, Adam Greene, and Pedram Amini. Fuzzing: Brute Force Vulnerability Discovery. 2007. Addison-Wesley. ISBN 0-321-44611-9.
[Takanen2008] Takanen, Ari, Jared D. Demott, and Charles Miller. Fuzzing for Software Security Testing and Quality Assurance. 2008. Norwood, MA: Artech House. ISBN-13 978-1-69693-214-2.
[Ted] Ted. Analysis of openssl freelist reuse. http://www.tedunangst.com/flak/post/analysis-of-openssl-freelist-reuse
[Uberti] Uberti, Justin. Untitled blog post. https://plus.google.com/+JustinUberti/posts/Ah5Gwb9jF4q
[Wheeler2004] Wheeler, David A. Secure Programming for Linux and Unix HOWTO. 2004. http://www.dwheeler.com/secure-programs/
[Wheeler2013] Wheeler, David A. Vulnerability bidding wars and vulnerability economics. 2013-11-16. http://www.dwheeler.com/blog/2013/11/16/#vulnerability-economics
[XKCD] Munroe, Randall. “Heartbleed Explanation”. XKCD. http://xkcd.com/1354/
随时观看我的主页http://www.dwheeler.com,您可以看下的文章“为什么OSS/FS”看看页码,和我的书《如何开发安全程序》。
一如既往,这是我的个人意见,我的意见和政府,雇主的意见不同。像往常我的写作一样,我使用是逻辑大多数黑客和维基百科都是这样做的。