关键要点
- 应用层加密是将更多基础设施和IT职责转移到开发人员或DevOps角色的趋势的一部分。
- 端到端加密是一种越来越流行的应用层加密类型。
- 这种类型的加密使组织能够使用密钥管理和策略来实施访问控制。
- 根据平台的不同,安全地向最终用户交付代码是非常不同的;基于浏览器的JavaScript是最具挑战性的。
- 使用这些方法可以极大地改善隐私和安全性,因此尽管存在挑战,但这是非常值得的。
任何处理敏感用户数据的人都生活在对数据泄露的恐惧中。我们知道加密可以减少负面影响,但大多数加密都被降级到TLS和VPN等基础设施级别的元素,而不是应用程序层。应用层和端到端加密可能是我们工具包中的一个强大工具,但作为开发人员,我们如何在不引入错误或降低数据实用性的情况下安全地将加密添加到应用程序中?
在本文中,我们讨论了应用层加密的优缺点。我们将介绍浏览器中应用层加密的攻击面,它与本地客户端的区别,以及WebCrypto的帮助。
威胁形势
违规行为的声誉、财务和人员影响可能极高。有助于保护最终用户隐私的新法律是向前迈出的重要一步,但它们可能会带来毁灭性的罚款。
研究表明,加密是减少数据泄露影响和成本的最有效的技术安全措施之一。当攻击者获得加密的数据集时,他们要么必须攻击另一个系统才能获得密钥,要么必须使用元数据和侧通道信息而不是“好东西”
加密通常侧重于“基础结构层”元素,如TLS、VPN、数据库加密标志和全磁盘加密。这些都是我们工具箱中的重要工具,但它们依赖于对基础设施的假设,而不是应用程序代码本身。
事实上,如果你考虑一下最近的数据泄露,至少在老牌公司中是这样,他们肯定在使用TLS和静态数据库加密,但泄露还是发生了。例如,Capital One最近遭到黑客攻击,敏感金融信息被盗。谷歌照片意外地让错误的用户访问了其他用户的照片和视频。这些错误本可以通过应用层或端到端加密来防止,或者至少可以减轻。
作为开发人员,基础设施不是我们的强项,有时也不是我们的工作,因此加密退居功能之后。但对于我们这些真正关心深入防御的人来说,在应用程序本身添加加密是很有意义的。应用层加密可以使我们的系统免受基础设施级别故障、TLS的已知弱点和一些服务器端漏洞的影响。
加密左移:什么是应用层加密?
将更多的安全性、操作和测试转移到开发过程中的做法(称为左移)正在提高软件的灵活性、可靠性和效率。这也意味着,安全性最佳实践需要作为应用程序开发的一部分来实现,而不是在出现问题时事后考虑。然而,绝大多数开发人员都不是安全或密码学专家,同时,安全团队对IT和开发的安全态势的控制比以往任何时候都要少。
应用层加密,或称加密左移,就是这一趋势的一部分。这意味着让开发人员对加密内容和解密密钥有更多的控制权。在某些情况下,用户自己可能是唯一拥有密钥的一方。在其他情况下,应用层加密可以在数据管理上添加访问控制层,提供深度防御。
正如名称所暗示的那样,应用层加密直接添加到应用程序的代码库中,并且对密钥材料的访问由应用程序逻辑控制。因此,您可以认为数据本身在其整个生命周期中都是加密的,而不是依赖于它在加密的网络或磁盘上。
最广泛理解的应用层加密是Signal和WhatsApp提供的端到端加密聊天,所以让我们思考一下这些应用程序是如何工作的。它有点过于简化了,但基本上是这样工作的:
nd-user action |
Access Control Logic (Server) |
App-layer Cryptographic Operation (Client) |
Add a friend |
Create an access control rule where users are allowed to send each-other messages |
Trust the friend’s cryptographic key |
Write the friend a message |
Create an access control rule where the friend can read the message |
Encrypt the message with the friend’s key (and sign it) |
Read a message from a friend |
Check for permission to download the message |
Decrypt a message with end user’s key (and check the signature) |
在这个简单的例子中,我们已经可以看到应用层加密的一些威力:
- 用户考虑的是他们想与谁交谈,而不是访问控制或加密,但事实上,用户正在做出策略决策。
- 访问控制逻辑是用密码学(并由谁拥有密钥来定义)强制执行的,而不仅仅是攻击者可能使用的服务器上的规则。
- 服务器无法访问纯文本数据,因此针对服务器的攻击,如SQL注入、内部威胁和根级别泄露,无法泄露数据。
请注意,这是一个端到端加密的示例,但并非所有应用层加密都是端到端的。此外,像这样的应用程序仍然需要TLS和其他基础设施层加密来强制执行身份验证、防止重放攻击以及解决许多其他问题。
为什么TLS还不够
当我们考虑TLS时,我们想象数据在其源处被加密并在服务器上被解密。但这种过度简化掩盖了TLS的实际局限性。
传输中加密的现实忽略了静止数据的加密,这影响了传输两端的安全性。它还完全忽略HTTPS终止后数据会发生什么,这些数据可能比你所知道的更位于网络边缘;例如,在您的负载平衡器上。
那么,在应用程序的其他点进行加密呢?如果你的加密工作高于平均水平,那么你已经在应用程序中编写了健壮、测试良好的代码来加密静止的数据,你已经在网络上使用了HTTPS和IPSec,并且启用了透明的数据库加密。
使用这种方法,我们几乎可以“处处加密”,但随着数据在系统中的移动,它在每一步都会被解密和重新加密。每一个接触纯文本数据的点都是一个潜在的漏洞,导致一个巨大的攻击面,你必须问问自己,“为什么这些中间服务无论如何都需要纯文本数据?”他们可能不需要。
基础设施层加密也会造成安全漏洞,因为基础设施的意外部分可能会获得数据。例如,即使你的数据库是加密的,你的数据库和磁盘备份也可能不会被加密。或者你的健康监测系统可能会以明文形式记录敏感数据,甚至(可怕的是)可能会将其发送给第三方。之所以会出现这些安全漏洞,是因为不同的个人或部门在以下各个方面负责安全:
- 在移动端,您的开发团队或供应商必须编写一些代码(或者至少实现HTTPS权限)。或者你的移动设备管理(MDM)系统封装了数据,或者你可能依赖用户检查“加密电话”框和操作系统供应商在那里做一些明智的事情。
- 在网络中,IT或DevOps负责提供证书并确保HTTPS配置良好,这并不总是那么容易。
- 在你的服务器上,你指望IT和DevOps来确保对你系统的内部访问,你指望云提供商和数据库供应商来实现“透明”的数据库加密。
这些解决方案中的每一个都使用不同的密码、库和密钥大小。你指望很多人把很多事情做好。这是个问题。
提供值得信赖的代码
加密是关于通信的;数据由一方写入和加密,然后由另一方接收和解密。发送方和接收方都必须有一个知道如何进行加密和解密的应用程序,并且可以信任它来正确地进行加密和加密。但这说起来容易做起来难。
如果加密代码是恶意的怎么办?攻击者能做什么?最简单的攻击是让应用程序完全按照预期工作,但也会将未加密的消息发送给坏人。当然,更微妙的攻击是可能的;添加隐藏的漏洞来削弱加密,篡改公钥等等。但它们都是一样的:一点代码可以帮助坏人获得秘密信息。
那么,让我们来谈谈代码交付。对于两个在手机上使用应用程序进行通信的人来说,信任链是这样的:一个好的程序员编写好的加密代码,将其编译成应用程序,用数字签名对应用程序进行签名,然后通过TLS将其上传到应用商店。用户通过TLS下载应用程序,操作系统检查数字签名是否“可信”,用户运行应用程序进行加密通信。请注意,该协议本身就是一个应用层加密数据交换。像DebianLinux这样的系统有类似的协议来安装和升级服务器和桌面应用程序。
受信任的应用程序下载可能会出现许多问题:用户可能下载了该应用程序的恶意版本。操作系统供应商可能会破坏对应用程序数字签名的检查。攻击者可以诱骗用户安装旧的易受攻击的应用程序版本(或不升级)。任何这些类型的攻击都会使端到端加密通信受到怀疑。但在大多数情况下,这很有效。
应用程序级加密通常在移动设备、笔记本电脑或服务器上运行的本地代码中实现,并且可以使用这样的协议来提供可信的代码。但现代应用程序通常都有一个主要的基于浏览器的组件,即使是对极为敏感的信息也是如此。
那么网络呢?
网络上的代码交付模型看起来与应用程序完全不同。当用户决定要进行安全对话时,他们会访问网页。浏览器通过TLS按需下载一些JavaScript。除了警告用户TLS连接不正确之外,这就是代码传递标准协议的结束。它完全依赖TLS。交付的JavaScript需要执行应用程序层加密,并且不能有任何恶意代码将未加密的文本发送给坏人。
为什么这是个问题?举个例子,我们的安全声明是,数据在一个浏览器中被加密,在另一个浏览器上被解密,而在没有警告标志和烟花熄灭的情况下,介于两者之间的Web服务器无法看到数据。要破坏这一声明,服务器只需在应用程序启动时发送恶意JavaScript。因此,能够控制提供代码或DNS和TLS各个方面的服务器的攻击者可以在不破坏任何加密的情况下发起此攻击。坏代码只能发送到特定的目标,这使得安全研究人员很难检测到。
事实上,随着应用程序更新和不断集成的速度,针对移动应用程序和台式机的类似攻击也是可能的。许多现代应用程序使用动态代码技术实时向应用程序传递至少一些代码;许多桌面应用程序可以随意更新自己的代码。这使攻击者能够在不同的时间点劫持代码更新,但也使安全团队能够快速修补。也就是说,基于浏览器的攻击被更好地理解了。
安全和密码学界的一些人指出这个问题,说你不应该进行基于浏览器的加密,或者如果你这样做了,你就不能声称它是端到端安全的。或者至少,它制造了一种虚假的安全感。我们不同意。确实存在弱点,但作为开发人员,我们无论如何都应该这样做,因为简单地说,人们使用网络是出于安全关键目的。
为什么浏览器中的应用层加密仍然具有良好的安全性
尽管存在代码传递问题,但在浏览器中进行应用层加密可以显著提高任何系统的整体安全性。原因是安全性不是全部或全部。在现代服务器基础设施中,很少有一个浏览器只与执行每项任务的单个web服务器对话;现代系统比这更复杂。
例如,假设您的web应用程序使用HTTPS并进行基于浏览器的端到端加密,但它存在SQL注入漏洞。此漏洞的本质是攻击者欺骗应用程序欺骗数据库转储敏感数据(具有讽刺意味的是,通过HTTPS)。但在我们的示例中,数据是端到端加密的,因此数据库只包含加密消息。如果没有应用层加密,坏人会得到更敏感的东西:纯文本消息。请注意,仅凭此漏洞,攻击者就无法更改代码以注入恶意JavaScript;基于浏览器的加密代码仍然健全。
另一方面,如果攻击者在API服务器上利用远程代码执行漏洞,可以随时修改JavaScript或向其中注入恶意代码,则他们可以通过添加向自己发送纯文本数据的代码来破坏端到端加密。
这只是两个例子,一个是应用层加密可以被破坏,另一个是不能被破坏,但端到端加密还可以防止无数其他攻击:也许你有一个太爱管闲事的员工,他在寻找名人的私人信息,但却无法访问代码。也许您将Postgres数据库备份到S3存储桶中,并意外地将其打开在web上。也许攻击者可以破坏TLS,但他们只是被动行动;他们可以窃听,但不能进行代码注入。
正如我们所看到的,浏览器中的应用层加密提供了深度防御,尽管代码交付存在挑战。在下一节中,我们将讨论缓解这些挑战的方法。
改进浏览器的可信代码交付
有许多方法可以提高浏览器中应用层加密的安全性。第一道防线是使用好的、可信的代码。现代应用程序开发要快得多,因为我们重复使用了在网上找到的大量代码,但如果用户浏览器中运行的任何代码是恶意的或易受攻击的,就会严重破坏加密。
保护提供代码的服务器也是至关重要的。在该服务器上分配访问控制权限时,请使用最小权限原则。对管理和代码部署使用多方控制。这将大大降低内部攻击的风险。
还有一些使用不足的代码传递设置指示浏览器采取额外的预防措施。它们不是默认的,因为它们在一定程度上降低了开发和集成过程的灵活性,但无论您的应用程序是否加密,它们提供的安全性都是值得的:
- HTTP严格传输安全性(HSTS):指示浏览器始终通过HTTPS加载此页面。这可以防止降级攻击,例如,如果攻击者可以将您的DNS重定向到恶意服务,则无法将连接降级到未加密的HTTP。
- 严格的内容安全策略(CSP):用于加载代码的白名单安全源。在现代JavaScript的复杂世界中,这会阻止应用程序从您不知道的远程资源动态加载代码。
- 子资源完整性(SRI):只加载您知道可以信任的脚本。这使用加密哈希来标记受信任的脚本。如果攻击者修改加密应用程序的JavaScript,这将更改哈希,并且不会加载代码。
此外,还有一种相对较新的浏览器API,它有助于高效和安全地传递加密原语。WebCrypto API提供低级密码、哈希和其他加密组件。这很有帮助,因为您不必在JavaScript中包含这些密码。浏览器直接实现它们,并可以利用本地本地执行甚至硬件加速。它不能阻止某些攻击,比如向坏人发送未加密的数据副本,但WebCrypto确实使基于浏览器的加密更加标准和可访问。
其他陷阱
安全的代码交付并不是实现应用层加密的唯一挑战。最大的问题是,大多数加密库相对难以安全使用,并且难以在不同的编程语言和平台中一致实现。当你在浏览器中加密并在应用程序上解密时,你可能需要三种不同语言(Android、iOS和JavaScript)的不同实现,它们都使用完全相同的密码和模式。
这些模式的安全操作不是很容易理解。例如,备受喜爱的AES密码是安全的,但将其与ECB(Java中的默认模式)等不安全模式配对是不安全的。将AES与GCM配对被认为是最佳实践,但即使是GCM也有其缺陷;如果使用相同的密钥加密过多的数据,或者初始化向量/noce出错,那么实际上可能会泄露密钥材料,这是其他模式所没有的缺陷。
一个错误可能会使你的加密数据无法恢复,甚至更糟的是,被坏人恢复。
另一个挑战是,如果你把加密数据放在数据库中,它就不再是可搜索的了。你必须提前计划好你希望数据库做什么样的查询和向下选择,或者你希望你的应用程序做什么。例如,如果你加密用户的家庭地址,你不能简单地用字符串“Oregon”为所有行选择*。如果按州向下选择是你应用程序工作流程的一部分,你可以加密用户的整个地址,但是添加一个未加密的元数据字段及其状态,这样您仍然可以执行此查询。从那里,您可以潜在地使用应用层逻辑来解密记录并执行其余的搜索,但数据库并没有多大帮助。
与我交谈的人经常关心应用层加密的性能,但这并不是一个重要的问题。加密速度很快,而且现在硬件的速度往往加快了。毕竟,我们使用HTTPS来流式传输整个社交网络的照片和视频,并没有真正注意到性能的影响。这在应用程序层是类似的,您不太可能发现加密是一个瓶颈。
可以肯定的是,仍然存在针对应用层加密的攻击。各国政府已将运营加密服务或安装加密应用程序定为非法或法律上不切实际的行为。用户选择弱密码或重复使用的密码可能会完全破坏加密。用户忘记密码也是一个难题;在这种情况下该怎么办?用户是否应该能够通过重置密码的电子邮件恢复他们的数据?这本身就削弱了端到端加密的论点。
当然,一旦数据被解密,攻击者就可以攻击终端设备本身。2019年WhatsApp发生了这种情况,让一些人怀疑端到端加密是否值得或重要。但事实上,攻击者必须针对特定个人对WhatsApp进行零日攻击,这足以证明端到端加密有帮助。
如何成功
在应用程序中实施加密时,您需要考虑您的特定安全目标、您可能必须遵守的任何合规规则,以及您需要谁拥有密钥材料。加密技术非常适合您的应用程序。受过训练的密码学家可以帮助你了解你的方法的优点和缺点,没有任何杂志文章可以告诉你什么是对的或错的。然而,你可以做出一些选择,让你更接近“好的密码学”,而且你通常可以安全地使用它们。
首先简要介绍一下三种主要的密码系统——对称、非对称和哈希。对称(共享密钥)快速高效,这些算法通常是加密数据的基线。AES通常是您想要的。
- 对称加密在密钥管理方面面临挑战。您需要一种方法来获得双方的共享密钥,这就是为什么您需要非对称加密。对称多块模式的保密性和完整性各不相同,有些模式在不同类型的数据或不同的系统约束(例如缺乏随机数生成器)下工作得更好:ECB、GCM、CBC、SIV等。
- 非对称(公钥/私钥)加密比对称加密更慢、更复杂,这些算法通常用于交换对称密钥。RSA是这里的“经典”选择;ECC更现代、更高效,而且几乎同样得到广泛支持。大致来说,公钥用于加密数据和验证签名。私钥用于解密数据和生成签名。
- 哈希、加密签名和消息身份验证码(MAC)提供了完整性。哈希生成一个短字符串,证明数据没有改变,或者在消息身份验证码的情况下,证明持有密钥的人对数据进行了“签名”。许多人认为加密意味着完整性,但事实并非如此。例如,AES默认情况下不提供完整性。像SHA2、Poly1305和GCM这样的算法会有所帮助。
管理密钥本身就是一个很大的话题,但需要考虑以下几点重要事项:
- 生成:密钥的随机性、大小、对称与非对称等。
- 存储:是从用户生成的密码派生密钥,还是将其存储以供以后查找。如果存储,您是否有一个安全的地方来放置它们,如钥匙链或硬件安全模块(HSM)?许多操作系统和平台现在都支持安全密钥管理。
- 通信:如何在客户端和服务器或两个用户之间就密钥达成一致。这对对称密钥来说非常困难,但对公钥来说也是一个挑战。公钥不需要是秘密的,但你必须相信它们确实来自你认为它们来自的人。为此,你需要已经有了可以信任的东西,这可能是一个鸡和蛋的问题。
除了关键材料之外,还有其他与加密消息相关的随机性或唯一性元素。初始化向量、salt和nonce属于这一类。这些也需要与解密方通信,因此需要存储或传输。通常,将这些未加密的内容与密文一起传输是安全的,但您应该小心,不要让攻击者修改它们。
您还需要对消息进行填充、编码、序列化和签名。信不信由你,即使是糟糕的填充也会破坏加密消息的机密性。对于JSON对象或HTTP标头等结构化数据的签名,双方都需要相同的方式来序列化和反序列化数据,否则签名将不匹配。
如果你做对了所有这些,你现在就有了一条加密和签名的消息。此时,您可能希望将此消息发送给另一方,后者将检查签名并解密消息。这意味着你需要交流你的所有选择:密钥id、大小、密码、模式、IV、哈希算法等。这种交流本身在许多密码学系统中是一个令人担忧的弱点。例如,攻击者能够诱骗一些对称系统表现得像非对称系统,并将其共享密钥直接发送给攻击者。哎呀。
我们有一些建议,特别是如果您需要或希望坚持使用NIST/FIPS-140密码,这些密码有时是政府工作或银行业合规所必需的:
- 对称加密:AES-GCM是一种很好的操作模式,因为它提供了多块机密性(与ECC不同)和身份验证/完整性(与CBC不同)。它广泛可用,所以当你需要它时,你通常可以指望它在那里。不过,你必须非常小心GCM nonce,因为nonce重用(或者如果攻击者可以选择它)可能会泄露密钥材料。这不好。
- 身份验证:这验证拥有私钥的人是否对数据进行了加密。非常重要。我们的建议与上述相同,使用GCM添加的标签。
- 密钥交换:曲线P-384上的椭圆曲线Diffie-Hellman(ECDH)是一个不错的选择。
- 哈希:如今,SHA256是相当标准的。
- 不要使用旧的/坏掉的东西:虽然这不是一个详尽的列表,但最常用的“旧的或坏掉的”东西包括:DES、MD4、MD5、SHA1、RC4、AES-ECB,(RSA是旧的,但不是坏掉的。如果有,可以使用,但如果可以的话,更喜欢ECC。)
- libSodium:如果你不需要NIST/FIPS合规性,你肯定应该研究libSodium。它非常受欢迎,而且这些库通常比实现类似FIPS密码的库更容易使用。
结论
加密是一种非常有效的数据保护方式,但目前部署的大多数加密都是IT基础架构的一部分,而不是应用程序的一部分。作为开发人员,我们有一个独特的机会,通过将应用层加密作为我们工具箱的一部分,来提高用户的隐私和安全性。确实存在一些挑战;加密数据可能更难管理,大多数加密库对于未经培训的开发人员来说都很难使用,但对我们的用户来说,这是值得的!
术语表
以下不是这些术语的正式定义,而是彩色注释,以帮助您了解这些术语和技术如何适用于应用层加密。
- 高级加密标准(AES):最常见的对称加密标准之一。
- 非对称加密:也称为公钥加密。速度较慢,但在密钥管理方面比对称加密更灵活。算法包括ECC和RSA。通常用于协商对称加密密钥。
- 块密码模式:由于像AES这样的对称密码只处理固定数量的比特(例如128),因此必须使用处理多个块的安全方法。不正确使用此类模式是一个常见的漏洞。常用的块模式有GCM、ECB(尽管它不安全)、CBC、SIV等。
- 域名系统(DNS):用于(通常)根据服务器名称识别服务器的协议。DNS是安全基础设施的关键部分,因为对DNS的控制可以让攻击者向最终用户模拟服务器。
- FIPS 140/NIST密码:由美国联邦政府审查用于各种用途的密码集合。一些行业要求使用经过审查的密码和实现。美国国家标准与技术研究院(NIST)将这些标准化。
- 硬件安全模型(HSM):用于安全管理加密密钥和操作的工具包。硬件层提供了额外的保护,例如防止特权利用。
- 初始化向量、salt和nonces:在加密算法中用作组件的随机数。根据算法和模式的不同,每种方法都可以具有不同的安全属性和用途。
- 完整性:一段数据不能更改的安全属性,或者如果它已经更改,则可以检测到更改,或者证明消息是由授权方生成的。MAC以及SHA2、GCM和Poly1305等算法可以帮助提供这种特性。
- 对称加密:类似AES的算法,双方使用相同的密钥进行加密和解密。比对称加密更快,但更难管理密钥,因为密钥需要在安全通道上交换。
- 传输层安全性(TLS):“传输中”通信加密的广泛标准。有时被称为HTTPS,但也适用于VPN等其他协议。
- 虚拟专用网络(VPN):对基于网络的通信进行加密。它保护用户行为的更多方面,而不仅仅是HTTPS,并且经常使用类似的技术。
Tags
最新内容
- 12 hours ago
- 14 hours ago
- 14 hours ago
- 3 days 5 hours ago
- 3 days 13 hours ago
- 3 days 13 hours ago
- 3 days 13 hours ago
- 3 days 14 hours ago
- 1 week ago
- 1 week ago