凌晨2点,在安静的房间里,你的孩子已入睡,你的另一半还在沙发上等着你,却已经睡着好一段时间。电视的灯光还闪烁在你的眼角。你的身心已极度疲惫。你为
今晚所取得的进展感到欣慰,并提交了代码,它包含过去几个小时的成果:“[master 2e4fd96] 固定安全漏洞
CVE-123”。你把你的更新上传至你的主机服务器,这样其他人就能在天亮后进行的关键版本发布之前,去查看和评论你的更改。挂起(待机)你的电脑,再
去把你的另一半摇摇醒,让他/她去床上睡。你再去关掉灯,却因为在卧室里被一个玩具绊倒,然后因为你的孩子听到了他/她最喜欢的玩具发出的声音,你不得不
去为他/她泡奶喝。 四小时严重不足的睡眠时间快速过去,你被你设定的手机震动声唤醒。你拍了拍你的脸,想了想你的闹钟,然后,迟钝地从床上爬出来,合上床头柜。(哎!你可能 再次把你的孩子吵醒。)你拿起手机,一个疯狂的同事在向你打招呼,“我把我们变更的代码合在一起了,我们需要一个标签打在这个地方”。啊,该死!让你醒来 的另一半,叫他/她去照顾一下哭泣的孩子(嗯,进展顺利!),跌跌撞撞地打开你的电脑,困难地键入你的密码,揉揉你的眼睛,把更改的东西给下下来。 你眯着眼瞥了一下,变化像洪水一样涌向你。房间里充斥着孩子尖锐的哭泣声,你的另一半无奈地用 微弱的气力去尝试控制局面。git log --pretty=short...每一样东西看起来都不错——你的同事和你的提交,已经在一个分支上被合并。你运行测试包——一切都通过了。看起来你已 经准备好了。git tag -s 1.2.3 -m '各种各样的修正, 包含关键的 CVE-123' && git push --tag。 经过努力输入密码到你的私钥,在你键入之后,缓缓地从你的椅子上站起来,跑去帮忙照顾孩子(天啊,他们把这些源代码放哪儿了),你的CI系统将会处理剩下 的东西。 快进两个月的时间(两个月之后)。 CVE-123补丁已经被覆盖很久了并且部署地很成功。但是,你收到了同事一个愤怒回应。看起来,你的一个重点用户有一个巨大的安全漏洞。在研究这个问题之后,你的同事找到了这个问题的根源,根据历史日志,漏洞利用了一个你创建的后门! 什么?你从来没想过这个。更糟的是,1.2.3还是你签署的,使用的是你的GPG钥匙(key)——你还确认过当初打这个标签是有效的是有准备的。“3-b-c-4-2-b,混蛋”,你的同事调侃的说,“非常感谢你啊”。 不——那没有意义。你快速地检查历史提交。git log --patch 3bc42b. "为X,Y和Z添加缺失的文档块。"你在困惑的表情中,抬起你的手,轻微地敲了几下键盘空格键,不带任何期待。果然,一些次要的文档块改变了,有一行非常 不起眼的代码改变了,导致一个后门被添加进了认证系统。提交信息清楚的显示,没有添加任何红色标记——为什么你不检查一下?此外,提交的作者真是你自己! 你的脑中各种思绪在飞奔!怎么会发生这种事情呢? 那次提交是你的名字,但是你没有回忆起那些曾经的变更。而且,你感觉没有改过那行代码;但,这是没有意义的。难道是你的同事在陷害你,让你提交的?还是你 的同事的系统被盗用了?还是你的电脑被盗用了?它没有在你的本地存储器上;那次提交是很清楚的合并部分,并没有存在在你的本地存储中,直到你追溯到那个两 个月前的早上。 不管发生了什么,有一件事情是极其可怕且清晰的,现在,你是那个被指责的人。 你相信谁?将你想要的理论化——或许你可能永远不知道是什么导致你的仓库(repository)危害的。上面的故事纯属虚构,但也是完全有可能的。怎么做才 能在休息的时候,保证你的仓库对引用(reference)或克隆(clone)它的程序员和可能下载它(例如,从它创建的压缩包)的人都是安全的。 GIT是一款分布式版本控制系统。简而言之,这意味着任何人可以私自拥有一份你的仓库的副本(copy)进行线下工作。他们可能提交版本到自己的仓库,也可以相互之间进行push和pull。中心仓库对分布式版本控制系统来说不是必需的,然而它可以作为一个“官方”中心仓库,其他程序员可以提交工作和克隆。因此,这也意味着某个广为流传的项目X的仓库可能含有恶意代码,就因为其他人交给你一个项目仓库并不代表你就应该实际使用它。 问题不是“我可以相信谁?”;问题是“我相信谁”,或者说你新人你的仓库,甚至你没意识到这一点。对大多数项目来说,包括上面的故事,有许多的个人或组织无意识的把信任放到没有经过充分考虑的决定的分支中:
不久以前(2012年3月4号),一个 GitHub的公钥安全漏洞被一个叫 Egor Homakov的俄国人利用了。这个漏洞允许他向GitHub上的 Ruby on Rails框架的主分支上提交代码。
假设,他们的网络是安全的、“干净”的。例如,一个愤怒的员工得到了自大的、讨厌的同事的名字/邮箱,并利用名字/邮箱进行了提交。如果你是经理或者项目领导,你该相信谁?你该去怀疑谁?
你使用你的电脑并不仅仅是开发,更多的是,你用它浏览网页、下载软件。并不是每个开发者都有较强的操作系统的安全意识。而且,简单的使用GNU/Linux或其它对*NIX系统并不意味着你对潜在的威胁具有免疫力。 探讨地更深入一点,让我们考虑一下世界上最大的开源软件项目——Linux内核——它的原创者Linus Torvalds是如何处理信任问题的。他2007年在谷歌的一次演讲中, 描述了其建立他和其他人(他指的是他的“助手们”)之间可信赖联系的事。Linus他本人不可能管理那些数量庞大的代码,因此有其他人帮助他处理内核的一 部分代码。这些“助手们”处理了大部分需求,之后提交给Linus,他来合并进他的分支。在这样的情况下,他已经信赖这些助手们的工作,他们会仔细地查看 每一个补丁,实际上Linus的很多补丁都来源于他们。 我不了解补丁从助手们到Linus是如何进行交流的。当然,一种可能的方式就是这些高水平经确认的补丁在他的“助手们”手中是通过E-Mail发给 Linus,然后他们再各自使用自己的GPG/PGP钥匙去确认签署。这说明,信任网络的执行是通过签名确认的。Linus来确保他私人的资源库(他尽他 最大的可能确保安全性,就前面提及的),这些库里包含的只有他私人信赖的数据。他的资源库是安全的,就他所知,他可以自信地使用它们。 在这一点上,假设Linus的关系网络信任是正确验证的,他怎么样才能将这些信任上的变化充满 信心地传递给其他人呢?他肯定知道他自己的提交,但是其他人怎么知道这个提交是“Linus Torvalds”这个人实际签署的呢?证明这个假设的场景在这篇文章的开头,任何人都可以宣称自己就是Linus。如果攻击者获取对存储库的任何克隆权 限的使用,并以Linus之名提交,就不会有人知道差异。幸运的是,一个人能绕过签署的标签,需要提供他/她私有的GPG钥匙(git tag -s)。一个标签指向一个特别的提交并且那个提交依赖整个历史记录的引入。这意味着那个签名的提交是用SHA-1哈希的,假设SHA-1没有安全上的缺陷,那么给定历史提交的状态将永远是指向那个信任的标签。 好吧,这是有帮助的,但是那不能帮助我们去验证所有的提交及其后面打的标记(直到下一个包含根的新标签的标签被打上)。这也不一定能保证所有过去的 提交是正确的——他只是表明,对于Linus来说这是最好的,这颗信任树是可信的。注意:在我们假设的故事中,我们一直使用他/她的私钥去签署标签。不幸 地是,他/她成了牺牲品,这太常见了——人为错误。他/她信任他/她的“信任”的同事,实际上能完全可信吗!即使我们从这个等式中移除人为的错误,这就很 完美了吗? |