用户作为安全风险的一个环节

  也许浏览器里突出(完全和技术无关)的一个特点是大多数使用者完全不懂技术。当然,打从计算机诞生之日起,电脑小白们一直是挺娱乐、挺无伤大雅的问题。但自从Web日渐深入人们的生活后,由于门槛极低,所以我们碰到了一个新情况:大多数用户对如何安全上网完全没概念。

  很长一段时间以来,工程师们在开发普通的软件时,一般来说是完全不会考虑到使用者的计算机水平的。大多数情况下这样做确实没什么大问题;比如某个文本输入框的数值不太对,对整个系统的安全性几乎没任何影响。如果用户的操作有问题,那他也多半玩不转这个软件,这也算是个极好的自我纠错机制了。

  但这套规律在Web浏览器上却行不通。和其他复杂的软件不同,哪怕使用者连文本编辑器都用不来,但使用浏览器却完全没问题。但同时,又只有对计算机技术和公开密钥体系(Public-KeyInfrastructure,PKI)这样的技术术语相当了解的人,才有可能安全地使用浏览器。不用说,在时下林林总总热门Web应用的目标人群中,绝大部分都不符合这一要求。

  而浏览器的许多做法,却弄得它像是由电脑极客们(geek)设计的,极客们使用的软件呢,譬如时不时蹦出一些难解又不连贯的出错提示信息,会涉及一堆复杂的配置,还有无数令人困惑的安全警告和提示。由伯克利和哈佛大学研究人员在2006年发布的一份的报告中显示,例如像状态栏上是否出现了带锁小图标这样的提示4,普通用户几乎肯定不会留意到这些信息,而开发人员却会非常清楚。在另一份研究中,斯坦福和微软的研究人员在检查新的“绿色URL地址栏”安全警示标识的功效时也得出了相似的结论。这个机制的本意是为了提供比带锁小图标更明显的安全标识,但结果也往往会误导用户,以为只要见到绿色的特定形状是可信的,也不管这种绿色标识出现在哪里5。

  有些专家认为,不能把普通用户的无知怪罪到软件开发商头上,因为这根本不属于软件工程的问题。但另一种观念是,既然这类软件随处可见且广泛使用,却要求用户必须自行判断许多安全相关问题,而这些问题得需要具备一定的技术知识,可在用户开始使用软件时又完全未做任何技术水平的限定,这是非常不负责任的做法。但仅指责浏览器开发商们也并不公平;毕竟计算机产业作为一个整体,在这个领域确实没什么靠谱的解决方案,要确保在复杂用户界面(UI)里的用户操作万无一失,也几乎没什么研究成果可供参考。毕竟,我们现在的水平还仅停留在勉强确保ATM级别的界面里不会犯错呢。

难以隔离的Web运行环境

  Web的另一个古怪特点是,完全无关的应用和应用相关数据之间的隔离度非常弱。

  在过去15年间,个人电脑时代的传统模式里应用层的数据对象(文档)、用户层的代码(应用程序)和操作系统内核之间的边界非常清晰,由操作系统内核负责所有跨应用程序的通信、硬件的输入/输出(I/O)以及通过可配置的安全策略限制应用程序的越界行为。这些边界已经被研究得很透彻,也确实对创建实际可用的安全策略大有助益。在文本编辑器里打开的文件,几乎不可能去窃取你的电子邮件,除非在具体实现上很不幸确实有重大缺陷,导致所有的隔离层都彻底失效了。

  但在浏览器的世界里,却压根不存在这种隔离:文档和代码交织在同一个HTML文件里,完全无关的应用之间多只能算部分隔离(实际上所有网站使用的是同一个全局JavaScript运行环境),除了要遵守寥寥几个灵活的浏览器级别的安全控制框架,不同网站之间各种交互都是隐式默许的。

  从某种程度来说,Web的这种模型与那些没有强壮的内存保护、CPU抢占或多用户支持的非多任务操作系统(如CP/M、DOS等)相类似。但明显不同的是,这些早期系统不太可能出现同时运行多个不受信任且易被攻击的应用的情况,自然也无需特别顾虑安全上的问题。

  所以在老系统里不太可能发生文本文件窃取电子邮件这种事情,但令人恼火的是,类似情况在Web上却屡见不鲜。实际上,所有的Web应用都曾为不请自来的恶意跨域访问,付出过沉重的代价,后只能用一些笨拙的方法勉强分离代码和要显示的数据。所有的Web应用都在这个事情上败下阵来,只是时间早晚而已。许多内容相关的安全问题,如跨站脚本(cross-sitescripting)或跨域请求伪造(cross-siterequestforgery)在Web领域都很常见,但在专用客户端的架构里,却极少碰到类似的情况。

缺乏统一的格局

  当然,幸运的是,浏览器的安全也不是完全无药可救了,尽管不同Web应用之间的隔离很有限,但某些安全机制还是为那些严重的攻击提供了基本保障的。说到这里,也带出了为何Web这一主题如此有意思的另一特点:因为它完全没有一个通用的整体性安全模型。在这方面,我们也没指望能有一个解决世界和平这么宏大的愿景,这里说的只是一些常规通用又灵活的安全范式集合,即使不能适用于所有场合,但可以解决绝大多数相关的安全逻辑行。例如,在UNIX系统里,rwx方式的用户/属组许可模式是这么一种高度统一的安全模式。但在浏览器领域里有什么呢?

  在浏览器领域里,“同源策略”(same-origin)机制可算是这类的核心安全范式了,但实际上这套本身问题多多的机制也仅是跨域交互里一个小的子集而已。即使仅讨论同源策略,也还有不少于7种的使用场景,这使得不同应用之间的安全边界也会略有差异。另外还有若干种机制,它们和同源模式没有什么关系,但控制了浏览器的其他关键行为(这些机制的作者往往是怎么容易实现怎么来)。

  所以结果是,有诸多这类零零碎碎耍小聪明的调整,但谁都无法担起浏览器的安全大任。由于缺乏真确性,也无从判断单个应用在什么时候结束,新的应用在什么时候开始。在这样的困境之下,到底怎样才算是出现攻击了呢?究竟是需要加载或取消权限许可,还是需要完成某项安全相关的任务呢?我们能做的,往往不过是“双手合十,听天由命,求个平安”而已。

  让人觉得奇怪的是,许多原本出于好意希望改善安全机制的努力,后效果却往往适得其反。为了获得优雅的效果,许多这类机制往往会引入新的安全边界,但这会导致与已混乱不堪的老的安全机制无法相匹配了。如果新的控制机制粒度更细,新机制则很可能会被老机制所拖累,带来的不过是一种虚幻的安全假象;如果新机制的粒度更粗,则可能导致连现有Web机制所依赖的微妙保障也没有了(AdamBarth和CollinJackson在他们的学术论文里讨论过浏览器不同安全机制之间的有害冲突)。

跨浏览器交互:失败的协同

  通常来说,一个包含多种应用程序的生态圈,整体的薄弱程度,可以简单地认为是每个软件产品问题的叠加。在某些场合里,总体的受影响程度甚至会小于这个叠加值(多样性使得可耐受性也提高了),但一般认为肯定不会超过所有问题的总和。

  但Web却再次打破常规。安全圈已经发现当多种浏览器企图彼此交互时,有一系列难以归咎到哪段具体代码头上但又非常严重的漏洞。你没法揪出哪个特定产品是罪魁祸首:它们都不过是在尽责地完成任务而已,问题是,没有为它们定义一个全体浏览器都理应遵守的公共规范。例如,某个浏览器认为,根据它的安全模式,把某个特定的URL传给外部程序或者存储/读取硬盘上某些类型的数据是安全的。对这类假设,几乎总有某个浏览器完全不认可,并且指望其他浏览器会按自己的规矩办事。而每个厂商也都希望把手伸得尽量长,所以往往会在未告知用户也未得到用户许可的情况下,强行用自家浏览器打开网页。例如,Firefox通过在其他浏览器里注册firefoxurl:协议,使得网页强行在它的浏览器里打开;微软则在Firefox里安装自己的.NET网关插件;而Chrome的做法和Firefox如出一辙,它会在IE浏览器里注册cf:协议。