保护内存核心机密数据的魔法,名字叫做……

保护内存核心机密数据的魔法,名字叫做……

故事从1883年说起,那一年,一位名叫Auguste Kerckhoffs的荷兰人用法语写了两篇文章,提出了6条军事上保密系统需要遵循的原则(也就是后来被大家在密码学领域奉为圭臬的Kerckhoffs's Principle),翻译成英文是:

  1. The system must be practically, if not mathematically, indecipherable;
  2. It must not be required to be secret, and it must be able to fall into the hands of the enemy without inconvenience;
  3. Its key must be communicable and retainable without the help of written notes, and changeable or modifiable at the will of the correspondents;
  4. It must be applicable to telegraphic correspondence;
  5. It must be portable, and its usage and function must not require the concourse of several people;
  6. Finally, it is necessary, given the circumstances that command its application, that the system be easy to use, requiring neither mental strain nor the knowledge of a long series of rules to observe.

如果你看这六条规则看得有点云里雾里,那用一句话来总结,就是:“密码系统的安全性应该仅仅依赖于密钥的安全( the security of a crypto-sysem should depend solely on the secrecy of the key)”

(信息论的祖师爷香农用一句更为简单明了的话来重新阐述了Kerckhoffs's Principle,图片来源:“The enemy knows the system.” - Cybermaterial)

随着时代的发展,大家越发意识到Kerckhoffs's Principle的重要性:对复杂的系统中的每一个细节进行保密既非常困难,同时一旦泄密也难以更换。而如果系统安全性仅仅依赖于很短的一串秘密信息,那么不但对其进行保密更为可行,且泄密之后可以用最小代价更新整个系统的安全性。因此,现代密码系统基本上都抛弃了传统的security through obscurity理念,采用了开放式设计,所有系统实现均可公开,更多地把安全性防护集中在对密钥的机密性保护之上。

上个世纪60年代到80年代,美苏争霸背景下,芯片、计算机和互联网这些本来是为了保证核威慑而研发的技术得到了飞速发展,后来成为了王者荣耀、Youtube和抖音的基础(捂脸)。此时,密码学也已经进入计算机时代,再也没有哪个加密算法和协议还依赖于人工操作,芯片和内存成为了加密运算的主战场,而密码系统在电子商务、加密通讯等领域也得到了广泛的应用,人们也开始逐渐将目光投向了网络和计算机世界中的机密信息保护,关心如何在新时代继续按照Kerckhoffs's Principle的指导思想来守卫关键系统的安全。可是,信息系统的变化,反过来却引发了一场针对Kerckhoffs's Principle的风暴!

时间来到2008年,当时还在普林斯顿大学,后来成为安全研究领域巨星的J. Alex HaldermanNadia Heninger两位80后研究人员共同完成了一篇Usenix Security当年的最佳学生研究论文

在这篇利用物理技术冷却被攻击设备的内存,并将其转移到其它系统上读取其中信息的论文中,有这么一幅图片胜过千言——内存中的数据在低温下并不会马上消失,而是“逐渐凋零”:

在此基础上,Nadia Heninger和Hovav Shacham很快在2009年的美密会上发表了另一篇论文Reconstructing RSA Private Keys from Random Key Bits,给出了一个非常具有震撼力的结论——攻击者只需要随机得到内存中RSA私钥27%的部分,就可以有很大的概率完全恢复整个私钥!

如果说这项研究工作已经对专业的安全研究人员针对内存中高度敏感的密钥信息防护敲响了警钟,那2014年的Heartbleed事件简直是为密钥安全防护敲响了丧钟!这个至今仍然在各种场合被反复提起漏洞,仅仅是因为OpenSSL代码中存在的内存破坏漏洞导致的内存信息泄露,在密码学完全无关的维度上对密钥防护一击致命,可以说是反过来利用了Kerckhoffs's Principle——攻击者只需要窃取数据量微不足道的密钥信息,就可以攻破整个密码系统的安全屏障!

研究人员发现,Kerckhoffs's Principle诞生之初,对密钥的安全管理完全是交给人工解决的,可是到了互联网时代,密钥和其它数据一样,都成了CPU和内存中无数需要处理的bit中的普通成员,这可完全对不起它那高度敏感的身份。于是铺天盖地的研究开始投入进来,想要确保这一内存中核心机密数据的安全。解决问题的法宝,是在2021年大家已经耳熟能详,但在2014年可能只是计算机安全研究专家所运用的基本方法——隔离(isolation)。

在计算机安全中,隔离策略本来就已经广泛运用在系统设计的几乎各个层面,例如操作系统对不同进程的物理内存的隔离,对不同用户的用户数据的隔离等。然而,针对密钥的隔离,并不只是一个简单的访问控制问题,更重要的一点在于,密钥本身可能被频繁访问,如果隔离机制带来的开销太大,也会让系统的运行慢到不可接受。因此,针对密钥保护的研究工作,通常会利用一些特定的软硬件隔离原语来辅助实现高效的访问控制。例如我们上海交通大学著名的IPADS实验室在2015年CCS上发表的研究工作Thwarting Memory Disclosure with Efficient Hypervisor-enforced Intra-domain Isolation中,提出了一个名为SeCage的系统,引入了虚拟化技术来对抗程序中可能发生的内存泄露,而在同年的IEEE S&P会议上发表的论文Protecting Private Keys against Memory Disclosure Attacks using Hardware Transactional Memory中设计的Mimosa系统,也同样利用了事务性内存操作(transactional memory)这个机制来确保密钥的访问不可被打断和非法访问。

可是,这许许多多发表在顶级安全学术会议上的研究工作,在针对内存核心机密数据——密钥的保护上,还忽略了什么呢?

2018年,G.O.S.S.I.P发表在当年CCS会议上、检测不安全密钥使用的论文K-Hunt: Pinpointing Insecure Cryptographic Keys in Execution Traces,在前人工作的基础上,第一次系统性总结了软件开发者在使用密钥时普遍存在的错误实践。而在这篇论文酝酿构思和写作的过程中,我们注意到了另一个更加严重的问题:

上图是从真实世界的软件中提取的一个实例,展示了程序如何由用户输入的口令(password)到最终转为加密数据时使用的AES密钥。在这个例子中,我们看到,输入的参数passwd经过了一个hash函数(hashstring)变换后,成为了一个32字节的keyblock,然后再经过xrijndaelKeySched这个函数的扩展,最终得到AES 256加密需要的15轮轮密钥(rkk结构体,其中每个轮密钥的长度是16字节)。

这个例子背后隐藏的事实是,在攻击者的视角看来,任何被标记为绿色的内存块(也就是图例中的Secret的含义)均包含了和密钥完全等价的信息量,也就是说,这一刻,伟大的Kerckhoffs's Principle不再完全正确了!攻击者并不一定需要针对AES的key(即例子中的keyblock)发起攻击,而完全可以转而攻击rkk或者passwd,同样可以完全恢复密钥信息!

这样的例子绝非仅仅影响AES算法(的某个特定实现),而是广泛影响着各类密码算法。Gabrielle De Micheli和Nadia Heninger在2020年的一篇综述性研究论文中,给出了一系列密码算法的密钥恢复技术:

看到这里,你是不是已经意识到了内存中的密钥信息的保护绝非一件容易的事情?确实,大量已有的研究工作(包括前述的SeCage和Mimosa),或者仅仅只考虑了密钥本身的保护,或者也意识到密钥本身会传播、扩散和复制,并引入了一些程序分析技术来进行追踪。但我们发现,目前没有一项工作,能够充分考虑密码算法的实现特点,因此无法精确地对程序中和密钥相关的敏感信息进行全面的标记、追踪和防护。

从2019年开始,G.O.S.S.I.P研究团队中四名年轻的同学金宣成、肖轩淦、贾淞淋和高旺开始对内存中密钥及其相关扩展数据的安全防护开展技术攻关,在长达一年多的研发过程中,攻克了多个挑战,研发了针对源代码中密钥及其扩展信息的静态标注和保护系统——CryptoMPK,能够自动化追踪和标记其中所涉及的需要保护的密钥及其扩展信息。我们首先实现了(可能是)历史上第一个crypto-aware的敏感数据传播分析

还是以上图的AES密钥生成为例,我们注意到,在这个例子中,经典的污点分析肯定会将密钥的污点传播到ciphertext中,而在密码学中,对于一个设计良好的加密算法,就算攻击者获得了明文和密文的所有数据,你也无法恢复密钥的哪怕一丁点信息。因此,如果使用的程序分析技术不考虑这种特定的传播,就会把密文(或者明文)也标记为敏感数据,然后自然就会带来严重的过保护问题(想想为什么?)

我们的crypto-aware敏感数据传播分析,巧妙地引入了一个“抵消”机制,除了在密钥上设置一个crypto tag以外,对明文和密文,我们请求开发人员手工标记一个额外的mxor tag,然后在敏感数据传播的过程中,当这两类tag相遇时,我们的程序分析会将生成数据的tag进行抵消(即information flow analysis领域中的declassification),这样就阻止了程序分析把明文和密文标记为敏感数据的不准确操作。


进一步,我们的分析工作还考虑了代码的上下文差异性,例如针对下图中的代码,我们看到xreadline这个函数,在被不同的父函数调用时,其安全的敏感程度是不同的。如果被readkey这个父函数调用,那么xreadline中包含的malloc就会分配一个和密钥相关的动态内存块,而如果是被另一个普通的父函数prompt调用,它分配的内存就并不需要保护:

我们的分析采取了context-sensitve的分析策略,针对不同的调用上下文,我们为同一个函数生成不同的copy,只对那些涉及到敏感操作的副本进行保护,进一步提高了保护的准确度!


最后,我们引入了Intel为服务器处理器定制的Memory Protection Keys (MPK) 隔离机制,能够非常高效地在需要访问密钥相关敏感数据的代码和其它代码之间频繁切换而不会带来太多的性能损耗


我们的实验数据测试表明,针对Apache/Ngnix+OpenSSL的HTTPS应用场景的保护,我们的隔离机制在极其细粒度的保护下,依然只会带来不到7%的性能开销!


我们研发的这套名为CryptoMPK的源代码静态分析系统,目前已经支持LLVM 10.0.1,值得注意的是,CryptoMPK的隔离机制和程序分析部分是高度解耦合的,也就是说,它完全可以应用其它一些平台的隔离原语(如ARM的Memory Domains)来实现不同硬件架构上的类似保护!


我们在整个研究过程中得到了加州大学河滨分校钱志云教授和张航博士、澳大利亚昆士兰大学马思奇研究员的宝贵支持,大家共同探讨并撰写完成了相关研究论文,这篇名为Annotating, Tracking, and Protecting Cryptographic Secrets with CryptoMPK的研究论文刚刚在今年7月初被IEEE旗舰级安全会议、也是公认的四大顶级安全学术会议中历史最为悠久的IEEE S&P录用,成为该会议2022年第一批投稿的245篇论文中,被录用的37篇(15.1%)论文之一!

我们的这篇研究论文中包含了对密钥信息及其扩展数据保护的大量丰富的细节内容,对本研究领域贡献了新的知识,欢迎大家关注我们这项研究工作,我们会在论文定稿后第一时间为大家推送PDF,也欢迎大家多多提问哦(通讯作者联系方式romangol@lijuanru.com)!

编辑于 2021-07-14 11:30