许多不同类型的程序可能需要成为安全程序(正如本书中定义的术语)。一些常见的类型包括
用作远程数据查看器的应用程序。用作查看器的程序(例如文字处理器或文件格式查看器)经常被要求查看由不受信任的用户远程发送的数据(此请求可能会由 Web 浏览器自动调用)。显然,不应允许不受信任的用户的输入导致应用程序运行任意程序。通常不建议支持初始化宏(在显示数据时运行);如果必须支持,那么您必须创建一个安全的沙箱(这是一项复杂且容易出错的任务,几乎永远不会成功,这就是为什么您一开始就不应该支持宏)。请注意缓冲区溢出等问题,这在第 6 章中讨论过,这可能会允许不受信任的用户强制查看器运行任意程序。
管理员(root 用户)使用的应用程序。此类程序不应信任可以由非管理员控制的信息。
本地服务器(也称为守护进程)。
网络可访问的服务器(有时称为网络守护进程)。
基于 Web 的应用程序(包括 CGI 脚本)。这些是网络可访问服务器的一个特例,但它们非常常见,因此值得拥有自己的类别。此类程序通过 Web 服务器间接调用,Web 服务器会过滤掉一些攻击,但仍然留下许多必须抵御的攻击。
小程序(即,下载到客户端以自动执行的程序)。Java 因这一点而闻名,尽管其他语言(例如 Python)也支持移动代码。这里有几个安全角度;客户端的小程序基础设施的实现者必须确保只允许“安全”操作,而小程序的编写者必须处理恶意主机的问题(换句话说,您通常不能信任客户端)。有一些研究试图处理在恶意主机上运行小程序的问题,但坦率地说,我对这些方法的价值持怀疑态度,并且这个主题足够冷门,我在此不再进一步介绍。
setuid/setgid 程序。这些程序由本地用户调用,并在执行时立即被授予程序所有者和/或所有者组的权限。在许多方面,这些是最难保护安全的程序,因为它们的许多输入都在不受信任的用户的控制之下,并且其中一些输入并不明显。
本书将这些不同类型程序的问题合并为一个集合。这种方法的缺点是,此处确定的一些问题并不适用于所有类型的程序。特别是,setuid/setgid 程序有许多令人惊讶的输入,并且此处的一些指南仅适用于它们。但是,情况并非如此明确,因为特定的程序可能会跨越这些边界(例如,CGI 脚本可能是 setuid 或 setgid,或者以具有相同效果的方式配置),并且一些程序被分为多个可执行文件,每个可执行文件都可以被认为是不同“类型”的程序。将所有这些程序类型放在一起考虑的优点是,我们可以考虑所有问题,而无需尝试将不适当的类别应用于程序。正如将要看到的,许多原则适用于所有需要保护安全的程序。
本书略微偏向于用 C 语言编写的程序,并附带一些关于其他语言(如 C++、Perl、PHP、Python、Ada95 和 Java)的注释。这是因为 C 语言是在类 Unix 系统上实现安全程序的最常用语言(CGI 脚本除外,CGI 脚本倾向于使用 Perl、PHP 或 Python 等语言)。此外,大多数其他语言的实现都会调用 C 库。这并不是暗示 C 在某种程度上是用于此目的的“最佳”语言,并且此处描述的大多数原则都适用于任何编程语言。