9.3静态数据的安全
数据加密是一种责任,尤其当它是敏感数据时。希望我们已经做了可以做的一切,以确保 攻击者不能攻破我们的网络,也不能攻破我们的应用程序或操作系统,然后近距离访问底 层数据。然而,我们需要做好准备,万一他们真的攻破了,我们该怎么办。深度防御非常 关键。
在许多有名的安全漏洞中,都发生了静态数据被攻击者获取的情况,且其中的内容对攻击 者来说是可读的。这要么是因为数据以未加密的形式存储,要么是因为保护数据的机制有 根本性的缺陷。
安全信息的保护机制是多种多样的,但无论你挑选哪种方案,有一些基本的东西需要 牢记。
9.3.1使用众所周知的加密算法
搞砸数据加密最简单的方法是,尝试实现你自己的加密算法,或甚至试图实现别人的。无 论使用哪种编程语言,都有被广泛认可的加密算法可供使用,它们都是经过同行评审,并 定期打补丁的。使用那些算法!并且订阅选择的算法的邮件列表/公告列表,以确保你知 道他们新发现的漏洞,这样就可以给算法打补丁或更新了。
对于静态数据的加密,除非你有一个很好的理由选择别的,否则选择你的开发平台上的 AES-128或AES-256的一个广为人知的实现即可。8Java和.NET运行时都包含AES的实 现,它们很可能都是经过充分测试的(和打好补丁的),但是对于大多数平台,也存在单 独的库,比如支持 Java 和 C# 的 Bouncy Castle 库(http://www.bouncycastle.org/) 。
关于密码,你应该考虑使用一种叫作加盐密码哈希(salted password hashing,https:// crackstation.net/hashing-security.htm#properhashing)的技术。
实现得不好的加密比没有加密更槽糕,因为虚假的安全感会让你的视线从球上面移开(双 关语)。
注8:通常来说,密钥的长度决定了暴力破解密钥所需的工作量。
因此可以认为密钥的长度越长,你的数据 越安全。
然而,受人尊敬的安全专家Bruce Schneier对于AES-256中某些类型的密钥实现表示担心 (https://www.schneier.com/blog/archives/2009/07/another_new_aes.html)。
你在阅读本书的时候在这方面 需要做更多的研究,以了解当前的建议是什么。
9.3.2 —切皆与密钥相关
之前已经讨论过,加密的过程依赖一个数据加密算法和一个密钥,然后使用二者对数据进 行加密。那么,你的密钥存储在哪里?如果加密数据是因为担心有人窃取整个数据库,那 么把密钥存储在同一个数据库中,并不会真正消除这种担心!因此,我们需要把密钥存储 到其他地方。但存到哪里呢?
一个解决方案是,使用单独的安全设备来加密和解密数据。另一个方案是,使用单独的密 钥库,当你的服务需要密钥的时候可以访问它。密钥的生命周期管理(和更改它们的权 限)是非常重要的操作,而这些系统可以帮你处理这个事情。
有些数据库甚至包含内置的加密支持,比如SQL Server的透明数据加密(Transparent Data Encryption),旨在以一种透明的方式处理这个问题。即使你选择的数据库已经这样做了, 也需要研究密钥是如何处理的,并且理解你要防范的威胁是否真的消除了。
再说一次,加密很复杂。避免实现自己的方案,花些时间在已有的方案研究上!
9.3.3选择你的目标
假设一切都需要加密,可以在一定程度上把事情简化,不需要再去猜测什么应该或不应该 被保护。然而,你仍然需要考虑哪些数据可以被放入日志文件,以帮助识别问题,而且一 切加密的计算开销会变得相当重,因此需要更强大的硬件。当你把数据库迁移作为重构数 据库模式的一部分时,这就更具挑战性。根据所做的更改,数据可能需要解密、迁移和重 加密。
通过把系统划分为更细粒度的服务,你可能发现加密整个数据存储是可行的,但即使可行 也不要这么做。限制加密到一组指定的表是明智的做法。
9.3.4按需解密
第一次看到数据的时候就对它加密。只在需要时进行解密,并确保解密后的数据不会存储 在任何地方。
9.3.5加密备份
备份是有好处的。我们想要备份重要的数据,那些我们非常担心的需要加密的数据,几乎 也自然重要到需要备份!所以它看起来像是显而易见的观点,但是我们需要确保备份也被 加密。这意味着,我们需要知道应该用哪个密钥来处理哪个版本的数据,特别是当密钥更改时。清晰的密钥管理变得非常重要。
9.4深度防御
正如我前面所提到的,我不喜欢把所有的鸡蛋都放在一个篮子里,而是做深度防御。我们 已经介绍了传输数据的安全以及静态数据的安全。但还有其他防护方法可以帮助我们吗?
9.4.1防火墙
有一个或多个防火墙是一个非常明智的预防措施。有些非常简单,只在特定端口限制特定 的通信类型。其他的则要复杂一些。例如,ModSecurity是一种应用程序防火墙,可以在 特定的IP范围限制连接数,并检测其他类型的恶意攻击。(ModSecurity是一个免费、开源的Apache模块,可以充当Web应用防火墙(WAF))
多个防火墙是有价值的。你可能决定在本地主机上使用IPTables,设置允许的入口和出口, 以确保这个主机的安全。这些规则可以根据本地运行的服务进行定制,而外围的防火墙则 控制一般的访问。
9.4.2 曰志
好的日志实践,特别是聚合多个系统的日志的能力,虽然不能起到预防的作用,但可以帮 助检测出发生了不好的事情,以便之后进行恢复。例如,在应用安全补丁后,你经常能够 在日志中看到是否有人曾经利用过某种安全漏洞。打补丁可以确保它不再发生,但如果已 经发生了,你可能需要进入恢复模式。
日志可以让你事后看看是否有不好的事情发生过。但是请注意,我们必须小心那些存储在 日志里的信息!敏感信息需要被剔除,以确保没有泄露重要的数据到日志里,如果泄露的 话,最终可能会成为攻击者的重要目标。
9.4.3入侵检测(和预防)系统
IDS (Intrusion Detection Systems,入侵检测系统)可以监控网络或主机,当发现可疑行为 时报告问题。IPS (Intrusion Prevention Systems,入侵预防系统),也会监控可疑行为,并 进一步阻止它的发生。不同于防火墙主要是对外阻止坏事进来,IDS和IPS是在可信范围 内积极寻找可疑行为。当你从零开始时,IDS可能更有意义。这些系统是基于启发式的 (正如很多的应用防火墙),很有可能刚幵始的通用规则,对于你的服务行为来说过干宽松 或过于严格。
使用在告警方面相对更加积极的IDS之前,应该先使用相对被动的IDS,因为在这种情况 下更容易优化规则。
9.4.4网络隔离
对于单块系统而言,我们在通过构造网络来提供额外的保护方面能做的很有限。不过,在 微服务系统中,你可以把服务放进不同的网段,以进一步控制服务间的通信。例如,AWS 提供自动创建VPN (Virtual Private Cloud,虚拟私有云)的能力,它允许主机处在不同的 子网中。然后你可以通过定义对等互连规则(peering rules),指定哪个VPC可以跟对方通 信,甚至可以通过网关把流量路由到代理中,实际上,它提供了多个网络范围,在其中可 以实施额外的安全措施。
这允许你基于团队的所有权或者风险水平来进行网络分段。
9.4.5操作系统
我们的系统依赖于大量的不是我们自己编写的软件,即操作系统和其他的支持工具,其中 的安全漏洞有可能会暴露我们的应用程序。在这里,基本的建议能让你走得很远。给操作 系统的用户尽量少的权限,开始时也许只能运行服务,以确保即使这种账户被盗,造成的 伤害也最小。
接下来,定期为你的软件打补丁。这需要自动化,并且你需要知道机器是否与最新的补丁 级別不同步。像微软的SCCM,或红帽的Spacewalk这样的工具,在这方面能提供帮助, 因为它们可以帮助你查看机器是否已更新到最新的补丁,如果没有的话发起更新。如果使 用像Ansible、Puppet或Chef这样的工具,很可能你对自动化推送更新已经相当满意了。 这些工具也可以帮助你走很长的路,但不会为你做一切。
这真的是最基本的东西,但令人惊讶的是,我经常看到很多重要的软件运行在未安装补丁 的、陈旧的操作系统上。你可能拥有世界上最好的受保护的应用程序级安全,但如果有一 个旧版本的Web服务器作为root用户运行在你的机器上,而机器没有应用缓冲区溢出的 漏洞补丁,那么你的系统仍然是极其脆弱的。
如果你正在使用的是Linux操作系统,另一件事是,看看操作系统本身安全模块的发展。 例如,AppArmour,允许你自定义应用程序的预期行为,内核会对其进行监控。如果它开 始做一些不该做的事情时,内核就会介入。AppArmour已经存在一段时间了,SeLinux也 是。尽管从技术上来说,它们俩在任何新版Linux系统上应该都可用,但实际上,某些发 行版对其中一个的支持会比另外一个要好。例如,Ubuntu和SuSE默认使用AppArmour, 而RedHat —直以来都支持SELinux。一个新的选择是GrSSecurity,旨在扩展AppArmour 和GrSecurity功能的同时,增加其易用性,但它需要一个定制的内核才能工作5我建议你 三个工具都看看,然后挑选一个最适合自己使用场景的工具,但我喜欢在工作中多加一层 保护和预防的想法。
9.5 —个示例
一个细粒度的架构,在安全实施上给了我们更多的自由。对于那些处理最敏感信息的,或 暴露最有价值的功能的部分,我们可以采用最严格的安全措施。但对系统的其他部分,我 们可以采用宽松一些的安全措施。
让我们再次考虑MusicCorp并结合之前的一些概念,看看可以在哪里以及如何使用这些安 全技术。我们主要考虑传输中的数据和静态数据的安全问题。我们即将分析的是图9-4显 示的整个系统中的一部分,目前欠缺对安全问题的考虑。一切都是通过普通的HTTP传输。
图9-4: MusicCorp不安全架构的一个子集
在这个例子中,我们的客户使用标准的Web浏览器,在MusicCorp网站上购物。我们还 引入第三方版税网关的概念:我们已经开始与第三方公司合作,为新的流媒体服务收取 版税。它会间断性地获取已下载音乐的记录——这个信息我们需要小心地保护,以防止 被竞争对手获取。最后,我们将产品目录数据暴露给其他第三方。例如,允许在音乐评 论网站中,嵌入艺术家或歌曲的相关信息。在我们的网络范围内,有一些协作的服务仅 在内部使用。
对于浏览器,我们会为无需安全保护的内容使用标准HTTP,以便其能被缓存。对于有安 全需要的、登录后才可访问的页面,所有的内容都通过HTTPS传输,这样,如果我们的 客户使用像公共WiFi那样的网络,能够给他们提供额外的保护。
当涉及第三方的版税支付系统时,我们所关注的不仅仅是公开数据的性质,还要确保我们 得到的请求是合法的。在这里,我们坚持让第三方使用客户端证书。所有的数据传输都通 过一条安全的、加密的通道,这能够提高我们确保请求主体合法性的能力。当然,我们也 需要考虑当数据离幵控制范围后,会发生什么事情。合作伙伴是否会跟我们一样关心这些 数据?
对于产品目录数据的聚合,我们希望尽可能广泛地共享这些信息,让人们很方便地从我们 这里购买音乐!然而,我们不希望这个信息被滥用,而且想要知道是谁在使用我们的数 据。在这里,使用API密钥是一个绝佳的选择。
在网络范围内部,情况有点微妙。我们有多担心有人威胁我们的内部网络?理想情况下, 最低限度也应该使用HTTPS,但是它的管理有点痛苦。我们决定,花费更多精力来夯实 网络边界上的防护(至少在刚幵始时),这包括使用一个正确配置的防火墙,选择适当的 硬件或软件安全装置检查恶意流量(例如,端口扫描或拒绝服务攻击,denial-of-service attacks) 0
也就是说,我们担心的是数据及其存储的地方。我们并不担心产品目录服务;毕竟,我们 希望共享这些数据,并为它提供了一个API!但是我们很担心客户的数据。在这里,我们 决定加密客户服务中的数据,并需要在读取时解密。如果攻击者真的潜入我们的网络,他 们仍然可以发送请求给客户服务的API,但当前的实现并不允许批量检索客户数据。如果 这个情况真的发生,我们可能需要考虑使用客户端证书来保护这些信息。即使攻击者攻破 数据库所在的机器,下载了全部内容,他们也将需要访问用于加密和解密数据的密钥才能 使用这些数据。
图9-5显示了最终的结果。正如你所看到的,基于对被保护信息本质的了解,我们最终选 择了这些技术。你自己的架构安全关注点很有可能非常不同,所以最终你可能会有一个看 起来不一样的解决方案。
9.9内建安全
就像对待自动化功能测试那样,我们不想把安全留给一组不同的人实现,也不想把所有的 事情留到最后一分钟才去做。帮助培养开发人员的安全意识很关键,提高每个人对安全问 题的普遍意识,有助于从最开始减少这些问题。让人们熟悉OWASP十大列表和OWASP 的安全测试框架,是一个很好的起点。不过,安全专家也绝对有用武之地,如果你能联系 到他们,可以让他们来帮助你。
有些自动化工具可以帮助我们探测系统漏洞,比如发现跨站脚本攻击。ZAP (Zed Attack Proxy)就是一个很好的例子。它由OWASP出品,尝试重现对网站的恶意攻击。一些 其他工具使用静态分析,寻找可能会导致安全漏洞的常见编码错误,例如针对Ruby的 Brakeman (http://brakemanscanner.org/)。这些工具可以很容易地集成到日常的CI构建中, 以及标准的代码签入过程中。其他类型的自动化测试相对来说比较复杂。例如,像Nessus 之类的漏洞扫描工具,它需要人为来解释运行结果。也就是说,这些测试仍然是可自动化 的,但以类似运行负载测试的节奏来运行它们,可能比较合适。
微软的安全开发生命周期(Security Development Lifecycle, http://www.microsoft.com/en-us/ sdl/default.aspx)也有一些很好的模型来帮助交付团队内建安全。其中一些内容似乎过于瀑 布了,不过还是值得参考的,看看哪些方面可以融入到你当前的工作中。
9.10外部验证
对于安全,我认为进行外部评估的价值很大。由外部方实施的类似渗透测试这样的实验, 真的可以模拟现实世界的意图。这样做还可以避幵这样的问题:团队并不总能看到自己所 犯的错误,因为他们太接近于问题本身了。如果是一个足够大的公司,可能有一个专门的 信息安全团队帮助你。如果不是,找一个外部方也可以。早点接触他们,了解他们是如何 工作的,并向其学习做一个安全测试需要关注哪些内容。
你还需要考虑,每次发布前需要多少验证。一般来说,并不是每次小的增量发布都需要做 一个完整的渗透测试,可能大的变化才需要。你的需求取决于你自己能承担的风险。
9.11 小结
我们再次回到本书的核心主题:把系统分解为更细粒度的服务,让我们在解决问题上有 更多的选择。微服务不仅可能会减少任何安全破坏的影响,它还给予我们更多的能力对 数据敏感的情况,采取幵销更大、更复杂和更安全的方案,而当风险低时,采用更轻量 级的方案。
一旦你了解系统不同部分的威胁级别,就可以知道什么时候需要考虑传输中的安全,什么时候需要考虑静态安全,或根本不用考虑安全。
最后,理解深度防御的重要性。给你的操作系统持续打补丁,即使你认为自己是一个摇滚 明星,也不要尝试实现自己的加密算法!
如果你^想要一个基于浏览器的应用程序安全的基本概述,优秀的非营利的OWASP (Open Web Application Security Project,开放式 Web 应用程序安全项目,https://www.owasp.org/) 是一个很好的起点,其定期更新的十大安全风险文档,应被视为所有开发人员的必备读 物。最后,如果你想要获得关于密码学的更全面的讨论,请查阅由Niels Ferguson、Bruce Schneier 和 Tadayoshi Kohno 所著的 Ctyptography Engineering。
逐步了解安全的过程,往往也是理解人以及他们如何使用我们系统的过程。关于微服务, 还有一个与人相关的方面没有做讨论,就是组织结构和系统架构之间的相互影响。正如安 全一样,我们会发现,忽视人的因素会是一个严重的错误。