到了2015年,为什么我们仍然在写不安全的软件?(节译)
英文原文:It's 2015. Why do we still write insecure software?
我已经看了大量编程方面的博客,如果你在看本文,那么你可能也看了很多博客。让我预先告诉你,这不是你通常的、归结为“再加把劲儿!”的安全论 调。让我们讨论一下聪明的、有经验的程序员,他们正在尽量编写安全的代码,即使他们本身不是安全方面的“专家”。这是重要的一群人,因为世界上要写的安全 相关的软件,比能够被安全专家编写的软件要多得多。
在一个理想的世界,假定为目标群体将结束本文。你的浏览器滚动条出现在全屏视图里,本文还要继续一段时间。唉,数十年的经验和被训练过的相当高的智商,对于在当前编码环境里去编写安全的软件,仍然是不充分的。
这也是最高量的资历,可能承受任意合理的规模,那么,实际上这等同于说,在当前编码环境编写安全的软件是不可能的。
让我们讨论下为什么这么难。我的观点很简单:
我编写不安全的软件,因为我们的编码环境造成的,它使得编写不安全的软件比编写安全的软件更加容易。
不过搞清楚它的真正涵义,会把你带到一些让人惊奇的地方。当我尽量向你展示为什么这不是一般地真实的时候,请跟着我,不过实际上,这是彻头彻尾 地真实。我们不是偶尔使用不安全的工具,比如被破坏的加密程序、或滥用 web 框架;我们是在不安全的海洋里游动的鱼儿,我们侵泡得有多深就很明显了。
首先,我必须确认……
编写安全的程序是有难度的
我们在工作中都有有限的感知预算。我们多么想拥有摇滚歌星或武士的神秘力量,可惜我们都不是。不管我们变得多么有经验,用 3 个 token 而不是 100 个,以花费较少的感知预算。想少些努力而尽可能完成一个任务,这不是“懒惰”,而是认识到资源总是有限的事实。
他们需要多少感知上的努力来编写代码,对此去检查一下编码环境,这是合理的事情。用这种方式彼此比较环境,是合理的。与工具无关、唯一相关的是程序员的技能,这种想法的论调要抛弃掉,这是合理的。
(花絮:在编程界,因为某种原因,大家对于格言“笨拙的工匠才会责怪他的工具”有着通常的误解,他们认为责怪其工具的人恰恰被证明为笨拙的工 人。这句话的真正意思是,把糟糕工具放在首位的工匠才是笨拙的。技能娴熟的工匠不会毫无怨言地使用钝锯子。他们会毫无怨言地找到或做一把好锯子。使用笨拙 工具而没有抱怨的工匠,甚至比只是抱怨的工匠还要糟糕!)
这里我们遇到一个问题,客观地测量一种语言所引起的认知成本,变得困难了,但是我认为,在实践中,“token 数”足够接近,在某种程度上这不是真实的,随着时间的发展,它越来越真实。(不幸的是,证明这一点将在另一篇文章介绍。超短版本:按照佛瑞德·布鲁克斯 【注1】的观点,在使用的常用语言,正在挤出它们偶尔的复杂性。因此让我再次强调:足够接近,而非完美。)因此大体上,正如我下面要讨论的“轻松”和“工 作”,你能够想象得到我正在讨论的“token 数”。
毕竟它是小型的、世界范围内可写的变量
让我们温习一个没有争议的例子吧,认知上昂贵的正确事情,是如何导致开发人员去做简单的错误事情:全局变量。正如我之前说过的,
所有程序员口头上都认为全局变量是糟糕的,然而神秘的是,即使没有人写过它,它们还是继续出现在代码库和资源库里(我谴责邪恶的代码精灵)。
现在我将解释为什么它们一直都出现。
(破坏者:它不是代码精灵。它们仅仅对 tab 和空格的混杂、以及偶尔的无礼的注释负责。)
我认为那是由于所有语言让全局变量单独成行,剩下的工作使得它比任何正确的工作要容易得多。
此时,文章结构似乎要让我向你展示设定一个全局变量是多么容易的例子,但是在大部分语言里,它是如此该死地琐碎,以致于羞于展示。但是不要说我接受的正规教育被浪费了,因此一味遵从其准则,就是:
variable = "value";
JavaScript 可以直接使用它。在 Python 里,分号是不相关的、但它能用。我怀疑只需两到三个 token,我就能搞定大部分命令式语言。甚至对于要求更多的语言,比如 Java,和做其它事情也是一样容易,因为不管你做什么,你将口口声声地说到 class。
同时,用全局值去做“正确”的事情是相当有难度的。它不得不被收集,并在各种难度的前提下传递,潜在地能够深入到数百行代码里,如果你需要修改 传递的类型,这就不是一个简单的问题了,这就是证据。没有人“想”使用全局变量,但是如果你想使它比本地“正确答案”更加便利,不管怎样,程序员将会使用 它们。甚至 Haskell 程序员们也抵制不了这个诱惑 unsafePerformIO $ newIORef 0。
相反,在很多语言里做正确的事情,超过了本文要讨论的,因为它充满了折衷,一定也涉及了很多 token。但是既然文章结构说到了这里,这里就是我为 Go 语言做的。看看它是多么容易地去做正确的事情,我都快眼晕了,然而,不可避免地它就是这么一行。(例如,Go 里的全局变量是:
var Global = "value"
放在最顶层。一个 var token 被加上了,名字不得不以大写字母开始。仍然比任何“环境”的使用简单。)
我借这个机会尽量去评判这个例子中的“token 数”的标准吧。当我们衡量一种语言在语法上怎样简单时,我们能够分解出“开发者能力”的问题。我们可以只是批评开发者做了错误选择,我们还能批评环境,因为它使得做错误选择太有诱惑。每个人都迷失了!
开始这个话题的优势在于,很少有人愿意公开赞同全局变量,大部分人都和我一样,认为他们更容易把事情“做对”;我傲慢地对着剩下的人挥了挥手。 在我开始有意思的讨论之前,请允许我花点儿时间重述一些我在这个没有争议的例子中的主要论点:不管我们都知道一个刚刚好的事实,它们更容易把事情做对,这 是错误的,我们仍然看到了如此多的全局变量。同时这可能听起起来还算明显,但是请注意,此时此刻所有事情都确定了,我们都在看待相同的事物,那就是我们正 在盯着一个兔子洞。
现在请穿上你的蓝衣服和白围裙,咱们开始吧。
哦……额……只需和平时一样,这是互联网,我看不到你。
(译者注:以下略去,有兴趣的读者可以自行阅读)
- 注1:佛瑞德·菲利普斯·布鲁克斯二世(英语:Frederick Phillips Brooks, Jr.,1931 年 4 月 19 日-),又译为弗雷德里克·布鲁克斯,生于美国北卡罗来纳州德罕软件工程师、学者,曾任万国商用机器公司(即 IBM 公司或国际商务用机器公司)系统部主任,主持开发过 OS/360 等大型电脑(计算机)用的操作系统软体。后来,布鲁克斯离开 IBM 公司,任教于北卡罗莱纳大学教堂山分校,担任计算机科学 Kenan 讲座教授,并著书立说。他所著的《人月神话》一书,被视为是软件工程的重要书籍之一。为 1999 年图灵奖得主。http://zh.wikipedia.org/wiki/%E4%BD%9B%E7%91%9E%E5%BE%B7%C2%B7%E5%B8%83%E9%AD%AF%E5%85%8B%E6%96%AF
— END —