保护程序员
我有一句最喜欢的格言:“如果你是系统管理员,你拥有王国的钥匙。如果你是开源程序员,你不知道你拥有多少个王国的钥匙,也不知道是哪些王国。” 我们将我们的程序发送到世界各地,供任何人出于任何目的运行。 想想看:任何人,出于任何目的。 你的代码现在可能正在核反应堆、导弹系统或医疗设备上运行,而且没人告诉你。 这不是猜想; 这是每天的现实。 举个例子:美国陆军在所有装甲车(坦克、装甲运兵车和增强型悍马)上安装了 gpsd,但没有告诉其开发者。
本文重点关注基础设施软件开发人员的需求——也就是说,任何以 root 身份运行、具有安全功能、保持整个互联网正常运行或具有生命攸关性的事物的开发人员。 当然,人们永远不知道自己的软件将在哪里运行或在什么情况下运行,所以即使你维护的只是一个幼儿登录管理器,也可以随意遵循本文的建议。 本文还涵盖了基本的安全概念和卫生:如何考虑安全需求,以及如何保持开发系统的良好状态,以减少重大计算机安全事故的风险。
本指南不会教你关于安全的一切。 它会给你一个关于做什么的想法,但在许多情况下,你需要依靠手册页和其他文档来获得“如何做”。 我这样做既是为了简洁,也是为了确保本文平等地涵盖各种 Linux 发行版,并且不会在几周内过时。
我在这里精心选择了控制措施。 这是一组在各种 Linux 发行版中始终可用的控制措施,对于开发人员来说是切实可行的,即使他们正在将开源软件作为副项目开发,并且无法投入太多时间。 它在不需要大量培训的情况下即可维护,并且对正在开发的软件的安全性具有最高的影响。 所有这些都是判断性的,我欢迎对此进行辩论。 本指南的目标不是“终极安全”或传说中的“无法破解的系统”。 它的目标是将开源基础设施软件开发人员的安全卫生标准从目前的水平显着提高。
我希望在一年后,我们都变得更加安全,并且可以再次迭代我们的标准。 在我理想的世界里,我每年春天都写这篇文章,我们都提高一个档次,然后在接下来的春天,我们准备好让勒索软件开发者、垃圾邮件发送者、压迫性政府、企业间谍等等的工作比以前更加困难。
概念我了解程序员——我自己就是其中之一——程序员不仅仅想被告知某件事有效,我们还想知道它为什么以及如何有效。 因此,在为开源开发人员介绍清单之前,我首先介绍一些基本的安全概念。
CIA 与软件开发
不,不是那个 CIA。 保密性、完整性和可用性:这些是安全的三个目标。 在开源世界中,我们通常最关心完整性:这是否是我信任的开发人员制作的软件,我可以确定它没有被篡改吗? 可用性通常排在第二位:我可以在需要时获得此软件及其文档的副本吗? 保密性通常排在最后,因为它仅适用于我们实践的几个部分:私钥和其他凭据、我们仍在努力修补的漏洞以及一些敏感的项目内部通信。 即使如此,这些事情也极少需要无限期地保密。
风险
“船在港湾里是安全的,但这并不是船的用途。”——威廉·G·T·谢德
我可以让我的笔记本电脑绝对安全。 我可以通过取出电池、用环氧树脂填充其端口、将其绑在一些砖块上,然后将其扔到马里亚纳海沟的底部来做到这一点。 在那里,在最深的海沟中,它将非常难以接近,任何试图接近它的人都会发现一堆粉碎的金属和塑料,它们无法承受压力或盐水。
当然,到那时,笔记本电脑对我或任何其他人有什么用呢?
计算涉及风险。 它一直涉及风险,但现在比以往任何时候都更加如此,因为我们不断连接并且运行的系统复杂到几乎无法审计。 我很少在范围如此小的机器上工作,以至于我可以一生审计其每一行代码,更不用说在下一个内核补丁发布之前了。 当我看到这样的机器时,它总是昂贵的单用途、生命攸关的组件。
尽管如此,世界似乎并没有走向末日(尚未)。 这是因为我们确实有能力将风险降低到可管理的水平
-
我们可以使风险变得无关紧要(如果我不存储信用卡号,我就不会面临信用卡数据库泄露的风险)。
-
我们可以将风险转移给其他人(如果我为笔记本电脑投保,保险公司会在笔记本电脑被盗时付款,而不是我)。
-
我们可以降低风险发生的可能性(如果我从不以明文形式传输或存储密码,那么密码被泄露的可能性就会降低)。
-
我们可以降低风险的影响(如果我使用双因素身份验证,那么仅泄露密码是没有任何作用的)。
控制措施是指在信息安全方面降低风险的措施。
全盘加密
“全盘加密”,通常缩写为 FDE,有点用词不当。 在大多数情况下,它实际上是指全分区加密。 许多发行版,例如 Red Hat 和 Ubuntu,在安装时都提供全盘加密作为复选框选项。 其他一些发行版,例如 Slackware 和 Gentoo,需要在准备磁盘时进行一些手动干预,但有相当好的文档可用。
既然您知道它有多容易,让我们来谈谈您为什么要这样做:加密所有存储(包括交换分区!)可以保护您免受计算机断电或休眠时被盗的风险。 如果您不使用 FDE,并且您的机器丢失或被盗,不仅您的个人信息会泄露,而且您的代码签名密钥、您用于签入代码和访问服务器的 SSH 密钥以及您可能拥有的任何尚未修补的漏洞的信息也会泄露。 攻击者可能会发布看起来像是来自您的补丁,而且很可能没有人会注意到。
对私钥密码的离线攻击可能会发生并且确实会发生。 全盘加密使密钥不太可能被恢复,并且几乎可以肯定您将有时间在此期间撤销它们。 它还为您的团队提供了充足的时间来修补和发布漏洞,然后窃贼才能利用您机器上的任何信息。
操作系统
很简单:如果您需要 Windows,请在虚拟机中或另一台机器上运行它。 不要在您的开发机器上双启动。 Windows 通常容易收集恶意软件,并且在机器直接启动到 Windows 的情况下(而不是在虚拟机中运行),Windows 可能有机会用恶意软件覆盖您主板的固件,然后这将影响您的 Linux 系统。
这并不是说 Windows 不能得到合理的保护,但它是一个庞大、难以管理的攻击面,特别是对于我们这些专注于 Linux 并且可能仅出于游戏目的而保留 Windows 系统的人来说。
密码管理
选择一个像样的密码管理器,并使用它。 重复使用密码是不可以的。 使用弱密码是不可以的。 没有人可以记住大量强密码。 通过只记住你必须记住的东西来节省你的大脑。
许多 Linux 用户问我,密码管理器真的安全吗? 如果我的密码保存在 RAM 中怎么办? 如果我的笔记本电脑被盗怎么办? 全盘加密将保护您机器的内容,包括您的密码管理数据库,并且大多数密码管理软件都有自己的加密层。 我不是在谈论完美的安全性(您可能希望将您最重要的 2-5 个密码保存在您的脑海中)。 我在谈论使体面的安全性变得可管理。 野外的弱密码比笔记本电脑上加密硬盘上的密码后面的密码管理数据库更容易受到攻击。
我可以写一整篇文章来讨论各种密码管理器的优缺点,但简短的版本是:任何不将您的所有凭据上传到云端的密码管理器都比不使用密码管理器要好。
密钥管理
您如何处理您的私有加密密钥对其有用性至关重要。 如果攻击者获得了您的某个密钥的副本——尤其是在没有双因素身份验证的情况下——他们可以轻松地离线暴力破解其密码并使用它来冒充您。 NSA 或中国或 EvilCorp 的最新后门可能会以您的签名发布。 因此,请执行以下操作
-
永远不要在没有全盘加密的系统上存储私钥。
-
除非您了解这样做的含义,并且有其他保护措施来防止其滥用,例如使用存储在单独硬件令牌上的密钥加密密钥,否则请避免创建无密码私钥。
-
记录您在哪里使用了哪些密钥,以便在密钥泄露时,您可以确保将其撤销并替换为新密钥。
-
在您的每台机器上使用不同的密钥。 如果您的某个密钥泄露,一旦使用,您就可以从哪个密钥知道您的哪台机器有问题。 如果所有机器都使用相同的密钥,您可能不知道泄露来自哪里。 当您让其他人为您撤销密钥时,拥有多个密钥也很有帮助。 如果我发现我的笔记本电脑的密钥可能已泄露,但我正在外出参加会议,我可以打几个电话来撤销该密钥在可能造成最大损害的两个或三个地方的密钥。 然后,当我回到家时,我可以通过我的台式机(它有自己的密钥)登录,以便在适当的位置为我的笔记本电脑放置一个新的公钥。
-
对于 GPG 密钥和其他允许它的系统,为每个密钥创建一个吊销证书,并让朋友存储这些证书以备紧急情况。 这样,即使您遇到重大泄露或无法访问您的私钥,您的朋友也可以将该密钥标记为已泄露且不再有效。 这不会让您的朋友能够冒充您,只能撤销您的密钥。
备份
您的备份应受到与您保护主系统相同的保护,否则它们与资产一样多地成为负债。 备份应始终加密,尤其重要的是,如果您备份到云服务,您必须配置备份系统,以便相关的加密密钥本地驻留在您这里,并且永远不会与存储加密数据的服务共享。 务必将备份数据的密钥或密码备份保存在安全且与该数据存储分开的位置,例如防火保险箱中,如果它们没有被记住。
多因素身份验证
很简单,多因素身份验证是您的朋友。 在任何可用的地方都使用它。 在大多数情况下,这是密码或 SSH 密钥与第二种身份验证因素的组合,例如硬件令牌、手机上的软令牌(提供时间敏感的短代码)或服务向您发送 SMS 或其他带外确认的能力。
密码相当容易泄露。 SSH 密钥则不然,但此时,双因素(或更多)身份验证已变得如此简单易用,没有理由不使用它。
GitHub、Google 和我们经常使用的许多其他服务都提供双因素身份验证,以帮助保护我们的帐户,并且还存在几种不同的选项,可以在我们自己的基础设施上使用它。
配置管理
如果您有一个足够复杂的系统,开销是值得的,请考虑使用配置管理系统,例如 Ansible 或 Puppet。 对于我们大多数人来说,就我们个人的开发机器而言,情况并非如此。 一个更简单、更轻量级的解决方案是安装并启用 etckeeper,它将在 git 或 hg 存储库中保留您的系统配置的修订历史记录,并在包管理器事件时自动更新它。 您可以在自己编辑配置文件时手动触发更新。
虽然 etckeeper 没有为您提供真正的配置管理系统的集中管理功能,但当与良好的备份结合使用时,它提供了对单机设置的安全性最重要的功能:配置的可审计性。 当出现问题时,该审计跟踪可能非常宝贵。
更新
跟上安全更新应该是理所当然的,但许多开发人员只是变得懒惰或避免更新,因为他们害怕他们将不得不解决一些新的冲突或故障。
但是,在一台安全补丁落后一周或更长时间的机器上进行关键开发工作,仅仅是为了方便起见,就代表您的软件的每个用户承担了巨大的风险。 您有包管理器; 请使用它。
防火墙
如果您的机器是一台将位于硬件防火墙后面的台式机,您可能不需要在机器本身上运行防火墙。 但是,如果您没有硬件防火墙保护您的机器,或者它是移动的(您随身携带的笔记本电脑,或者您曾经带到黑客马拉松或局域网派对的台式机),则需要对其进行防火墙保护。
几乎每个 Linux 防火墙都是 iptables 的包装器,这很好,因为 iptables 快速、强大且可靠。 您使用哪个包装器并不重要。 我已经使用 ipkungfu 一段时间了,以避免不得不在我的笔记本电脑上手动编写 iptables 规则,但其他选项也一样好。
SSH
您可能出于各种原因需要在您的开发机器之间进行 ssh
连接:传输文件、检查一个设置或从国外的笔记本电脑使用家庭构建环境。 有许多关于运行 SSH 服务器的优秀指南,但以下是一些关于您的 sshd 配置的初步检查的一般提示
-
除非您真的需要并且不让它在启动时启动,否则永远不要在您的开发机器上运行 sshd。 开发机器是您通常坐着的机器,因此在不使用时运行 sshd 是不必要的风险,并且在需要时很容易启动它。
-
永远不允许以 root 身份
ssh
登录。 如果您需要 root 访问权限,您可以以普通用户身份ssh
登录,然后使用su
或sudo
来获得 root 权限。 这有助于确保单个泄露的密钥或密码不会给攻击者 root 权限。 -
永远不允许仅使用密码的 SSH。 要么要求基于密钥的授权,要么要求密码加上第二因素,例如来自软令牌应用程序的一次性密码。
-
检查日志或运行监控脚本以随时了解暴力破解您的 sshd 的尝试。
隔离用户和服务
增加系统安全性的一个简单方法是使用系统帐户将各种服务彼此隔离。 有些发行版在大多数情况下默认执行此操作,但您应该检查您的机器是否在任何可行的地方都这样做
-
不要将 root 或可以无需密码(例如,通过无密码 sudo)行使 root 权限的用户用于日常任务。 始终为任何给定任务使用最少的系统访问权限。
-
不要以 root 身份在您的机器上运行每个服务。 一般来说,除非您必须这样做,否则永远不要以 root 身份运行任何内容。 开发人员经常出于测试和开发目的运行许多服务的本地实例。 这些服务应隔离到它们自己的 runs-as 用户,以帮助包含一个服务引起的任何暴露。 Apache 可能以“apache”或“www-data”身份运行; git 服务器可能以“git”或“gitolite”身份运行; 邮件服务可能以“mail”身份运行。 无论名称是什么,重要的是服务是分离的。
-
永远不允许两个用户共享同一个系统帐户。 系统帐户是免费的; 根据需要创建更多帐户。
不要在开发机器上使用的东西
-
如果您必须运行 Adobe Flash(尽量不要运行它),请仅在一个浏览器中启用它,并在另一个浏览器中执行您容忍 Flash 的一项以外的所有操作。 更好的是:如果可以,仅在专用于该目的的虚拟机中运行 Flash。 Flash 是闭源的,漏洞百出,根本无法安全。
-
不要运行 FTP 服务。 FTP 非常不安全,FTPS 也是如此。 这不应与 SFTP 混淆,SFTP 提供类似的功能,但在更值得信赖的 SSH 协议上运行。
-
禁用机器上的所有 FireWire 和 Lightning 端口,如果可能,在 BIOS 或 UEFI 固件中禁用,否则通过物理断开它们或用环氧树脂填充它们来禁用。 FireWire 和 Lightning 使用直接内存访问,这意味着攻击者在您参加会议并移开视线片刻(即使您的计算机屏幕已锁定)时连接到其中一个端口,只要您的机器已启动,就可以转储您 RAM 的内容(或更改它)。
-
工作站和备份上的全盘加密(包括交换分区)。
-
没有 Windows 双启动(虚拟机可以)。
-
使用密码管理器。
-
永不重复使用密码/密码短语。
-
为上下文使用合理强度的密码/密码短语。
-
没有密钥存储在未加密的介质上。
-
没有密钥以无密码方式存储(例外情况请参见文章)。
-
私有加密密钥永不委托给其他人(仔细检查云备份系统)。
-
所有密钥的吊销证书都与信任的朋友一起存储。
-
在任何可行的地方都使用 2FA。
-
2FA 令牌永不存储在用于登录或存储主凭据的同一设备上。
-
在所有系统上都采用了配置管理(至少是事后变更记录)。
-
root 用户或具有无限无密码 sudo 权限的用户不用于日常计算、编码等。
-
为方便/测试而运行的本地服务(例如 Web 服务器、gitolite 等)以其自己的用户帐户而不是 root 身份运行,并且仅有权访问其自己的目录中的文件,这已明确记录在案。
-
没有远程可访问的服务在启动时自动运行; 远程服务仅在需要时运行。
-
工作站上没有运行 FTP 守护程序。
-
SSH 的密码身份验证已禁用。 仅允许基于密钥或多因素身份验证。
-
以 root 身份 SSH 已禁用。
-
每次我走开时,即使只有一分钟,工作站屏幕也会锁定。
-
应用程序防火墙(可能是 iptables)已配置并在工作站上运行。
-
每周多次检查所有软件包的更新。
-
未安装 Adobe Flash(或在所有浏览器中禁用)。
-
Lightning 和 FireWire 端口在 BIOS/UEFI 固件设置中禁用。