第 7 章 病毒

目录

引言

Windows 的缺陷

Unix 的健壮

历史

引言

这是一个非常流行的言论:

Linux 下的病毒少,是因为 Linux 的使用者少,骇客显然不愿意浪费气力去攻击没有人使用的操作系统。

您可能已经知道了,互联网上用作重要用途的服务器,其中很大一部分是 Linux 系统,另外的一部分是 Unix 系统:) 如果骇客能够搞掉 Linux 系统的话,那么整个互联网就会陷于瘫痪!效果似乎更好一些。

当然了,您一定会想:骇客也是人,他们也喜欢上网,兔子还不吃窝边草呢……兔子那么笨,连乌龟都跑不过……骇客们可比兔子要聪明的多了!它们总没有理由让自己无家可归吧?

是的,我承认这一点……不过他们也不一定非得把互联网干掉。很多骇客作梦都想入侵美国军方的服务器,美军服务器中的绝密数据,我想拉登大叔一定愿意以重金买下的!

如果骇客可以入侵任何一台主机[16],他们为什么不去入侵美军的服务器,而要入侵您的电脑呢?

有些人又会认为:这样的解释不能说明什么,Linux 比 Windows 安全也许只是偶然的,或许下一个版本的 Windows 会超过 Linux。

个人倾向认为这种情况不可能出现,后面的论述基本摘自《UNIX 编程艺术》[17]

顺带提一下,与上面的观点相呼应,另一种论调也使人侧目:Windows 服务器占到了服务器操作系统xx%的份额。

或许这个现象可以用80:20法则来解释:

占服务器总数80%的 Windows 提供了服务总量的20%

请您务必注意,这只是举一个例子,Windows 服务器可能永远也不会占到服务器总数的80%!它提供的服务,以我个人的角度,我不认为可以达到20%,而且永远不会有那一天。


[16] 我看过一篇报道,美国海军的一个港口的指挥塔,以前用 Windows,每天不得不重启主机N次,后来实在扛不住,转用了 Linux。指挥塔只不过是指挥几艘小船靠个岸,负载不大,也不是特别重要,尚且不可以用 Windows,军方的中央服务器就更不可能了

[17] 这本书算是开源信仰的《福音书》,建议弄一本看看。由于这本书实在太长了,所以我就不全文摘抄了

Windows 的缺陷

尽管支持抢先式多任务处理,但进程生成却很昂贵——虽然比不上 VMS,但是(平均生成一个进程需要0.1秒左右)要比现在的 Unix 高出一个数量级。脚本功能薄弱,操作系统广泛使用二进制文件格式。除了此前我们总结过的,还有这些后果:

大多数程序都不能用脚本调用。程序间依赖复杂脆弱的远程过程调用(RPC)来通信,这是滋生 bug 的温床。

………………

Unix 的系统配置和用户配置数据分散存放在众多的 dotfiles(名字以“.”开头的文件)和系统数据文件中,而 NT 则集中存放在注册表中。以下后果贯穿于设计中:

  • 注册表使得整个系统完全不具备正交性。应用程序的单点故障就会损毁注册表,经常使得整个操作系统无法使用、必须重装。
  • 注册表蠕变( registry creep ) 现象:随着注册表的膨胀,越来越大的存取开销拖慢了所有程序的运行。

互联网上的 NT 系统因易受各种蠕虫、病毒、损毁程序以及破解(crack)的攻击而臭名昭著。原因很多,但有一些是根本性的,最根本的就是:NT 的内部边界漏洞太多。

NT 有访问控制列表,可用于实现用户权限组管理,但许多遗留代码对此视而不见,而操作系统为了不破坏向后兼容性又允许这种现象的存在。在各个 GUI 客户端之间的消息通讯机制也没有安全控制,如果加上的话,也会破坏向后兼容性。

虽然 NT 将要使用 MMU,出于性能方面的考虑,NT 3.5后的版本将系统 GUI 和优先内核一起塞进了同一个地址空间。为了获得和 Unix 相近的速度,最新版本的 NT 甚至将 Web 服务器也塞进了内核空间。

由于这些内部边界漏洞产生的协合效应,要在 NT 上达到真正的安全实际上是不可能的。如果入侵者随便作为什么用户把一段代码运行起来(例如,通过 Outlook email 宏功能),这段代码就可以通过窗口系统向其它任何运行的应用程序发送虚假信息。只要利用缓存溢出或 GUI 及 Web 服务器的缺口就可以控制整个系统。

Unix 的健壮

Unix 至少设立了三层内部边界来防范恶意用户或有缺陷的程序。一层是内存管理:Unix 用硬件自身的内存管理单元(MMU)来保证各自的进程不会侵入到其它进程的内存地址空间。第二层是为多用户设置的真正权限组——普通用户(非 root用户)的进程未经允许,就不能更改或者读取其他用户的文件。第三层是把涉及关键安全性的功能限制在尽可能小的可信代码块上。在 Unix 中,即使是 shell(系统命令解释器)也不是什么特权程序。

操作系统内部边界的稳定不仅是一个设计的抽象问题,它对系统安全性有着重要的实际影响。

彻头彻尾的反 Unix 系统,就是抛弃或回避内存管理,这样失控的进程就可以任意摧毁、搅乱或破坏掉其它正在运行的程序;弱化甚至不设置权限组,这样用户就可以轻而易举地修改他人的文件和系统的关键数据(例如,掌控了 Word 程序的宏病毒可以格式化硬盘);依赖大量的代码,如整个 shell 和 GUI,这样任何代码的 bug 或对代码的成功攻击都可以威胁到整个系统。

历史

大部分1980年前的 Unix 竞争者都被拴到单个硬件平台上,随着这个硬件的消亡而消亡。为什么 VMS 可以坚持这么久?值得我们作为案例研究一个原因是:VMS 成功地从最初的 VAX 硬件移植到了 Alpha 处理器(2003年正从 Alpha 移植到 Itanium 上)。MacOS 也在1980年代后期成功完成了从摩托罗拉68000到 PowerPC 芯片的迁跃。微软的 Windows 处在计算机商品化将通用计算机市场扁平化到单一 PC 文化的时期,真是生逢其时。

自1980年起,对于那些要么被 Unix 压倒要么已经先 Unix 而去的其它系统,不断重现的另一个特有弱点是:不具备良好的网络支持能力。

在一个网络无处不在的世界,即使为单个用户设计的系统也需要多用户能力(多种权限组)——因为如果不具备这一点,任何可能欺骗用户运行恶意代码的网络事务都将颠覆整个系统(Windows 宏病毒只是冰山一角)。如果不具备强大的多任务处理能力,操作系统同时处理网络传输和运行用户程序的能力将被削弱。操作系统还需要高效的 IPC,这样网络程序彼此能够通信,并且能够与用户的前台应用程序通信。

Windows 在这些领域具有严重缺陷却逃脱了惩罚,这仅仅因为它们在连网变得真正重要以前就形成了垄断地位,并拥有一群已经对机器经常崩溃和无数安全漏洞习以为常的用户。微软的这种地位并不稳定,Linux 阵营正是利用这一点成功地(于2003年)在服务器操作系统市场取得了重大突破。

在个人机刚刚进入全盛时期的1980年左右,操作系统设计者认为 Unix 和其它传统的分时系统笨重、麻烦、不适合单用户个人机这个美丽新世界,而弃之不理 ——根本不顾 GUI 接口往往要求改造多任务处理能力,来适应不同窗口及其部件的绑定执行线程的事实。青睐客户端操作系统的趋势非常强烈,服务器操作系统就像已经逝去的蒸汽机时代的遗物一样遭到冷落。

但是,正如 BeOS 设计者们所注意到的那样,如果不实现某些近似通用分时系统的东西,就无法满足普遍联网的要求。单用户客户端操作系统在互联网世界里不可能繁荣。

这个问题促使客户端操作系统和服务器操作系统重新汇到了一起。首先,互联网时代之前的1980年代晚期,人们首次尝试通过局域网进行点对点联网,这种尝试暴露了客户端操作系统设计模式的不足:网络中的数据必须放到集合点上才能实现共享,因此如果没有服务器就做不到这一点。同时,人们对 Macintosh 和 Windows 客户端操作系统的体验也抬高了客户所能容忍的最低用户体验质量的门槛。

到了1990年,随着非 Unix 分时系统模型的实际消亡,客户端操作系统设计者还是拿不出来多少可能解决这一挑战的方案。他们可以吸收 Unix(如 MacOS X 所做的),或通过一次一个补丁重复发明一些大致等价的功能(如 Windows),或试图重新发明整个世界(如 BeOS,但失败了)。但与此同时,各种开源 Unix 的类客户端能力不断增强,开始能够使用 GUI 并能在廉价的个人机上运行。

然而,这些压力在两类操作系统上并未达到上面描述所意味的那种对称。将服务器操作系统特性,如多用户优先权组和完全多任务处理,改装到客户端操作系统上非常困难,很可能打破对旧版本客户端的兼容性,而且通常做出的系统既脆弱又令人不满意,不稳定也不安全。另一方面,将 GUI 应用于服务器操作系统,所出现的问题却大部分可通过灵活处理和投入更廉价硬件资源得到解决。就像造房子一样,在坚实的地基上修理上层建筑当然要比更换地基而不破坏上层建筑来得容易。