这对于文件重定向器这样简单的网关而言,一切良好。但模拟常常用在其他更复杂的应用程序中。以一个 Web 应用程序为例。如果您编写一个经典的非托管 ASP 程序、ISAPI 扩展或 ASP.NET 应用程序,在它的 Web.config 文件中有如下指定 <identity impersonate='true'> 那么您的运行环境将有两种不同的安全环境:您将具有一个进程标记和一个线程标记,一般来说,线程标记会被用来做访问检查(见图 3)。假设您正在编写一个在 Web 服务器进程中运行的 ISAPI 应用程序,并假定大多数请求未经身份验证,则您的线程标记可能是 IUSR_MACHINE,而进程标记却是 SYSTEM!假设您的代码能被一个坏家伙通过缓冲区溢出利用。您认为他会只满足作为 IUSR_MACHINE 运行吗?当然不会。他的攻击代码很可能会调用 RevertToSelf 以删除模拟标记,从而希望提高他的权限级别。在这种情况下,他会很容易获得成功。他还可以调用 CreateProcess。它不会从模拟标记复制新进程的标记,而是从进程标记复制,这样新进程便可以作为 SYSTEM 运行。 那么怎样解决这个小问题呢?除了首先确保不出现任何缓冲区溢出外,还要记住最小授权原则。如果您的代码不需要具有 SYSTEM 这样大的权限,则不要将 Web 应用程序配置为在 Web 服务器进程中运行。如果只是将 Web 应用程序配置为在中等或较高的隔离环境中运行,您的进程标记将会是 IWAM_MACHINE。您实际上没有任何权限,因而这种攻击几乎不会生效。注意,在 IIS 6.0(即将成为 Windows .NET Server 的一个组件)中,默认情况下用户编写的代码不会作为 SYSTEM 运行。基于这样的认识,即开发人员确实会犯错误,Web 服务器就减少赋予代码的权限而提供的任何帮助都是有益的,以免万一代码中存在安全问题。 下面是另外一个 COM 程序员可能遇到的隐患。COM 有一个不好的倾向就是敷衍线程。如果您调用一个进程内 COM 服务器,而其线程模型与调用线程的模型不匹配,则 COM 会在另一个线程上执行调用。COM 不会传播调用者线程上的模拟标记,这样结果就是调用会在进程的安全环境中执行,而不是在调用线程的安全环境中。多么令人吃惊! 下面是另一个由模拟带来的隐患的情况。假设您的服务器接受通过命名管道、DCOM 或 RPC 发送的请求。您对客户端进行身份验证并模拟它们,通过模拟以它们的名义打开内核对象。而您又忘了在客户端断开连接时关闭其中的一个对象(例如一个文件)。当下一个客户端进入时,您又对其进行身份验证和模拟,猜猜会发生什么?您仍然可以访问上一个客户端“遗漏”的文件,即使新的客户端并没有获得访问该文件的权限。出于运行性能的原因,内核仅在第一次打开对象时对其执行访问检查。即使您后来因为模拟其他用户而更改了安全环境,您还是可以访问此文件。 以上提及的这些情况都是为了提醒一点,即模拟为服务器开发人员提供了方便,但这种方便却具有很大隐患。在您采用一个模拟标记运行程序时,务必要对自己的代码多加注意。 10. 编写非管理员用户可以实际使用的应用程序 这确实是最小授权原则的必然结果。如果程序员继续开发这样的代码,使得必须是管理员身份的用户才能在 Windows 上正常运行,我们就不能期望提高系统的安全性。Windows 有一套非常稳定的安全功能,但是如果用户必须具有管理员身份才能进行操作,他们就不能很好地利用这些功能。 您怎样进行改进呢?首先,自己先尝试一下,不以管理员身份运行。您很快就会知道使用没有考虑安全设计的程序的痛苦。有一天,我 (Keith) 安装一个由手持设备制造商提供的软件,该软件用于在我的台式机和手持设备之间同步数据。与往常一样,我退出了普通的用户帐户,然后使用内置的管理员帐户再次登录,安装了软件,然后再次登录到普通帐户,并且试图运行软件。结果该应用程序跳出一个对话框,说不能访问某个所需的数据文件,接着便给出一个访问冲突信息。朋友们,这就是某个主流手持设备厂商的软件产品。对这种错误还有什么借口吗? 在运行了来自 http://sysinternals.com(英文)的 FILEMON 之后,我很快发现该应用程序试图打开一个数据文件以进行写入访问,而该文件与应用程序的可执行文件安装在同一目录中。当应用程序如预想的那样安装在 Program Files 目录中时,他们绝不能试图向该目录写入数据。Program Files 具有这样一个限制访问控制策略是有原因的。我们不希望用户写入这些目录,因为这样会很容易让一个用户留下特洛伊木马程序,而让另一个用户去执行。实际上,这个约定是 Windos XP 的基本标志性要求之一(请参阅 http://www.microsoft.com/winlogo [英文])。 我们听到太多的程序员给出借口说他们为什么在开发代码时选择作为管理员身份运行。如果我们继续忽略这一问题,只会让事情更糟。朋友们,编辑一个文本文件并不需要管理员权限。编辑或调试一个程序也不需要管理员权限。在您需要管理员权限时,请使用操作系统的 RunAs 功能来运行緎com.asp?TARGET=/winlogo/">http://www.microsoft.com/winlogo [英文])。 我们听到太多的程序员给出借口说他们为什么在开发代码时选择作为管理员身份运行。如果我们继续忽略这一问题,只会让事情更糟。朋友们,编辑一个文本文件并不需要管理员权限。编辑或调试一个程序也不需要管理员权限。在您需要管理员权限时,请使用操作系统的 RunAs 功能来运行具有较高权限的单独的程序。(请参阅 2001 年 11 月的 Security Briefs [英文] 专栏)。如果您是在编写给开发人员使用的工具,那么您将对这个群体负有额外的责任。我们需要停止这种编写只有以管理员身份才能运行的代码的恶性循环,要达到这一目标,我们必须从根本上发生改变。 有关开发人员如何能够轻松地以非管理员身份运行的详细信息,请参阅 Keith 的 Web 站点 |