web|xml|攻击保护 XML Web 服务免受黑客攻击, []第一部分] [第二部分]
Matt Powell
Microsoft Corporation
2001 年 9 月 19 日
在上一篇文章中,我们讨论了不同种类的攻击,以及如何进行配置以免受到攻击。本文中,我们将集中讨论如何进行设计和开发,以免受到攻击。
首先,我想介绍两个非常好的新工具,它们是 Microsoft® 开发的,可使您的 Web 服务器获得最大的安全性。IIS Lockdown Tool(英文)可以最大限度地防止可能的攻击者对您的 Microsoft® Internet Information Server (IIS) 进行访问。锁定工具还提供了“advanced”选项,您可以在其中选择所需设置。此外还提供了“rollback changes”选项。当您对所做更改不满意时可选择该选项。请尝试该工具。
另一个重要工具是用于 IIS 5.0 的 Hotfix Checking Tool(英文)。该工具会查询由 Microsoft 发布的所有可用安全性修补程序的 XML 文档(该文档是不断更新的),然后将此文档与本机安装的文档进行比较并报告其差异。使用该工具可以更轻松地管理单个 Web 服务器或大型 Web 领域的安全修补程序。
设计问题
设计 Web 服务时必须认真考虑安全问题,以及如何能够使遭受攻击的危险性降到最低。许多在试图防止攻击时可能起作用的因素都可以在设计时予以考虑。例如考虑如何进行身份验证,或希望返回哪类错误等问题。
确定安全需求
在 XML Web 服务设计的早期,您需要确定所需的安全级别。某些 XML Web 服务根本不需要身份验证,而其他服务对于确定使用该服务的用户有非常严格的要求。由 XML Web 服务接收和发送的数据需要何种隐私级别?如果某个 XML Web 服务用户声明他们未请求您记录中所指明的服务,则在工时、处理能力或法律费用方面可能要花费哪些成本?
首先,让我们来看一下身份验证。某些种类的身份验证会比其他身份验证更容易遭受攻击。在低端,如果您使用“HTTP 基本身份验证”,则可以看到网络上的数据包的所有用户都能看到您的用户名和密码。如果通过 Internet 发送请求,则您无法控制能看到您的数据包的用户。在身份验证级别的高端,您可以考虑使用 SSL 客户端证书进行身份验证,该证书提供了一个编码的通道,并使数据包的恶意攻击者很难进行攻击。有关身份验证选项的详细讨论,请参阅 At Your Service 专栏中 Mary Kirtland 的 Authentication and Authorization(英文)。
我们已经间接提到了身份验证过程中的隐私问题,当涉及到电子欺骗时您应考虑此问题。您还需要知道与所有从 XML Web 服务发送和接收的数据有关的隐私问题,而不仅仅是用户名和密码。例如,您可能会为通过身份验证的用户生成一个会话密钥,该用户将此密钥随每个请求一起发送以标识自身。如果此密钥未加密发送,则数据包的恶意攻击者可以看到此密钥,并用它向您的 Web 服务发送自己的请求,这样您的 Web 服务会将其看作是原来那个合法用户。
另一个隐私问题是由 Web 服务发送和接收的简单数据。该数据是否因其敏感性强而需要加密?SSL 加密的代价是 Web 服务会发送和接收整个加密的通道,从而降低性能。您或许可以只加密请求中的敏感项,但您随后可能需要在客户端上安装自定义编写的软件以启用加密/解密。使用 SSL 加密整个通道的一个优点是:目前大多数客户端平台都支持基本 SSL 通信,而不需要针对应用程序编写特定代码。
就基本安全性设计而言,还必须考虑否认的概念,即一个用户可以拒绝承认其通过 XML Web 服务执行的操作。例如,如果您提供股票交易服务,而某些人声称他们没有要求您的系统为其出售股票,并且要否认此出售命令。很明显,与其他服务相比,某些 XML Web 服务对这种问题可能会更为关心,但是您应该确定您的服务可能会遇到的危险,以及在方案中应采取什么样的有效措施。
使用安全的身份验证系统肯定是避免出现这类危险的首要步骤。例如,使用 HTTP 基本身份验证可能是不安全的,但是通过使用 SSL 的加密通道来使用此身份验证则是安全的。如果用户使用空密码或容易猜到的密码,即使具有安全的身份验证系统也是没有用的。强制使用强加密密码是防止出现此类问题的重要步骤。总之,用户和服务执行者都有责任防止密码泄露。
最后,如果不审核通过服务发生的事件,当出现否认情况时,安全的身份验证和强加密密码都是毫无意义的。当事务中存在否认威胁时,应记录这些事务及其用户、时间、日期等足够多的信息以标识事务的详细信息。否则,当出现争论时,您可能缺少足够的证据以证实您的观点。
审核、报告和监视
审核对减少否认危险程度起着重要的作用;在识别其他种类的攻击过程中,也起着关键作用。例如,如果不是您的审核记录中的统计数据表明您的服务存在异常使用情况,您可能根本意识不到您的服务正在遭受攻击。例如,您是否注意到某个人正在对登录方式进行字典攻击?所以,我们将讲述在审核、报告和监视时需要考虑的问题,以保护 XML Web 服务免受攻击。
审核的概念就是记录所发生的每个事件的所有信息。但是,当通过 XML Web 服务的数据量很大时,此想法可能是不切实际的。审核记录至少应包括所有请求的时间、日期和 IP 地址。如果 XML Web 服务经过身份验证,您需要在每个审核记录中包括用户名。如果您的服务支持多种方法或消息格式,您需要标识调用的是哪一个。最后,您需要包括足够的信息以满足您标识调用详细信息的需要。例如,如果 XML Web 服务使用了一种方法,您可能希望记录传递给该方法的所有参数。
您还需要考虑其他需要,例如当站点遭到攻击时您可能需要回滚事务。而且,您的审核记录往往是某些报告的最佳信息源。由于审核记录可能相当大,您需要协调审核设计和备份策略。
审核处理的是通过您的服务同时发生的所有事件的记录,报告则是向用户、操作员和管理员汇报系统的使用信息。报告是保护 XML Web 服务免受攻击的一个重要部分,因为通过它可以观察服务的使用情况。一种主要的报告类型是报告发生的错误。报告 XML Web 服务所遇到的错误的能力是最重要的。同样,您还需要报告那些可能指出恶意客户端企图的错误。例如,如果所接收请求中的某个参数是一个异常的长字符串,则您需要以一种容易引人注意的方式来报告该错误。对于这种类型的错误,您应该在应用程序事件日志中创建事件,这样可以相应地对它们进行监视。有关如何将事件写入事件日志的详细信息,请参阅操作系统平台 SDK 中的 Event Logging(英文)。
另一种对您的服务至关重要的报告类型是汇总服务使用情况的报告。它应该有两种形式:首先,创建供您个人进行分析的全局报告,您可以使用该报告检测使用级别或异常模式。应该对正常报告的外观具有足够的了解,这样您才能够发现异常使用的情况。其次,需要为您的用户提供报告。您的用户还应能够监视他们对服务的使用情况。很有可能出现这样的情况:在全局报告中未记录攻击行为,而个别用户却能立即在其各自的报告中发现问题。
如果 XML Web 服务正在 Internet Information Server (IIS) 上运行,那么我们就有必要提及一种能免费得到的非常有用的报告类型。即,为所有传入的 HTTP 请求(包括对您服务的请求)进行的 IIS 日志记录。您可以使用 IIS 日志中提供的信息来改进自己的报告。 '
最后,实施了审核及适当的报告方法后,您需要使用某种机制以发现所报告的问题。这就是监视。
可以以不同级别进行监视。当然,定期手动查看报告是监视 XML Web 服务的使用情况的一种方式,但是还应检查事件日志中已报告的错误,使用性能监视日志,并利用可以监视 Web 服务器停机时间的多种工具中的一种。性能监视对于检测攻击可能是非常关键的。幸好,与 IIS 关联的大量性能计数器可以为检测问题提供许多重要的统计数据。
您可能还希望为 XML Web 服务创建自己的性能计数器。有关创建您自己的性能计数器的详细信息,请参阅 Performance Monitoring(英文)。为了确保引起您对异常情况的特殊关注,应以某种形式通知您正在发生的事件,这点是非常重要的。可以在异常事件发生时,利用性能监视警报发送弹出式消息,或运行某个程序。图 1 显示的性能监视警报会监视未完成的 IIS ISAPI 请求的数量,以及当前队列中的 ASP 请求的数量。
图 1:创建性能监视警报
如果不对可能发生的问题采取一些措施,则对滥用的操作进行审核、报告和监视不会有任何用处。拒绝服务攻击可能会被定义到特定的 IP 地址,这意味着您可能需要在路由器中过滤来自该地址的请求。但是,拒绝服务攻击或电子欺骗攻击可能与 XML Web 服务的特定用户相关。您必须能够在这种问题发生时禁用帐户。完成此操作可能仅需在 Microsoft® Active Directory™ 中禁用 Windows 用户帐户。或者,如果使用的是自己设计的身份验证方式,则意味着必须在用户记录中添加一个可以表示禁用帐户的状态字段。您还应确认 XML Web 服务的用户同意“服务条款”文档,该文档指明在何种情况下您可以删除或禁用他们的帐户。
定义接口
与其他 Web 应用程序相比,XML Web 服务器应用程序的一个主要优点就是很好地定义了传递到您的应用程序的整个 XML 架构。对于应用程序设计人员和开发人员来说,这意味着您已经知道 XML Web 服务所必须处理的数据具有有效的格式。如果接收的数据格式不正确,那么 Microsoft® SOAP Toolkit 2.0 或 .NET 框架之类的工具将过滤出该请求,这样您就不必为此担心了。
例如,您不必分析日期输入的语法是否有效。日期必须具有有效的 XSD 格式,否则该请求会被丢弃。您可能需要利用结构验证,因此不要隐藏字符串变量中的结构。利用 XML 的能力和灵活性可以全面描述发送和接收的数据。
不可见的服务器
黑客攻击您的系统时,首先寻找的是信息。此 Web 站点是驻留在 Windows 中还是驻留在其他系统中?是否正在运行 Active Server Pages?是否安装了 Index Server?是否安装了已知的易受攻击的组件?是否安装了已知的易受攻击的 CGI 应用程序?主机是否正在运行 Microsoft® SQL Server?我是否可以对此服务器进行分布式 COM (DCOM) 调用?
对于不希望受到攻击的站点,即使非常聪明的 Internet 用户也应该无法回答上述任何问题。黑客对您的系统了解得越少,对平台的了解也越少,就越难在您的服务器上找到问题。
例如,试想一下,如果黑客只知道 XML Web 服务的 URL 为“http://www.coldrooster.com/ssf/account.asp”,他们能了解什么呢。由于此 URL 的扩展名为 .ASP,他们可以假设这是一台运行了 Active Server Pages 的 Windows 计算机。根据黑客对 Internet Information Server 的默认配置的了解,他们已具有足够的信息对大量的未正确配置的弱点进行攻击。他们可对配置方法进行大量的、很可能有效的假设,并用这些假设来刺探计算机。
如果 URL 为“http://www.coldrooster.com/ssf/account/”,情况又会怎样呢?在这种情况下,黑客得不到任何服务器所用操作系统的信息,也无从假设系统的配置。将虚拟目录级的请求映射到某个特定的 ASP 页是一个非常小的配置选项,但能为服务器提供很多保护。
熟悉基本 HTTP 协议的用户可能注意到 HTTP 标头特别指明了正在使用的 Web 服务器类型。是的,这是另一种确定计算机上操作系统的更为复杂的方法,但是也可以编写 ISAPI 过滤器来删除或替换此标头。有关如何进行这种操作的信息,请参阅 Developing ISAPI Filters(英文),以及 IIS 程序员指南中的 SF_NOTIFY_SEND_RESPONSE(英文)通知。服务器上运行的基础系统越难辨认,黑客编写的用于在 Internet 上查找某种类型计算机的脚本失败的可能性就越大。
但是操作系统本身并不是唯一的弱点。您创建的 ASP 页在后端执行 SQL 查询并抛出异常时,会执行什么操作?您是否将异常信息返回给用户浏览器?这样不仅指出了 Web 服务器平台,还指出了数据库平台。除此之外,它还可以使用户了解您正在进行的特定 SQL 查询,并为他们提供信息,使其了解如何更改要输入到窗体中的内容以得到他们不应有权访问的信息。
出现其他 COM 异常情况怎么办?如果将异常信息传播给用户,黑客将会知道您的计算机上安装了哪些 COM 组件。如果此 COM 对象是第三方 DLL,则黑客可以得到它的一个副本,并竭尽全力搜索可能存在的所有弱点。这至少使黑客有机会了解服务器上可能存在的问题。
同样,黑客可能会利用触发 COM 异常这一事实来阻塞服务器。黑客意识到多数异常代码路径未经充分测试,且常常是资源泄露或变得更糟的起因。要避免出现这种情况,服务器上的代码应能捕获所有异常情况,并且应该只返回普遍性的错误。对于 XML Web 服务,您应返回几乎不带有平台信息的 SOAP 错误。您可能希望以某种方式将数据连同 ID 一起返回给用户以便将错误与审核日志中的记录进行比较,但是,请将错误详细信息放在审核日志中而不是放在返回的 SOAP 错误中。建议应用程序设计人员创建自己的应用程序的 SOAP 错误架构,同时提供一个非常短的选项列表,并且仅返回此列表上的错误。调用 XML Web 服务的客户端不必知道有关 SQL 查询异常的详细信息,他们只需要知道出现了 SOAP 服务器错误。
如果正在使用 Microsoft® SOAP Toolkit 2.0,可以在 COM 对象上实现 ISoapError 接口以返回您希望返回的确切的 SOAP 错误,而不是一般的工具包错误。一般的工具包错误可以提供大量的、有关错误出现时在服务器上所发生情况的信息。在开发阶段,工具包错误对于调试来说是很有用的,但是它们在产品服务器上不应出现。他们可以为黑客提供大量的、具有潜在破坏性的信息。
XML Web 服务的用户需要知道您的服务所发送和接收的 SOAP 消息的格式,以及您的服务的终点位置。这就足够了。任何其他信息都只会为潜在的黑客提供攻击手段以毁坏您的系统。要进行自我保护,应限制返回与平台有关的信息,并消除计算机上的多余内容,包括删除任何有助于他人识别您的系统的默认虚拟目录或脚本映射。
开发问题
对黑客来说,服务器的脆弱性与服务器上运行的代码质量是成反比的。它包括基础系统(操作系统、Web 服务器和正在使用的 SOAP 工具)的质量,以及为特定应用程序编写的代码的质量。还可能包括服务器上运行的所有其他代码,即使该代码不是应用程序的一部分。但是从开发人员的角度而言,我们希望考虑我们能控制的问题,以及能执行哪些特殊的操作以保证代码的高质量,避免增加 XML Web 服务和服务器上正在运行的其他所有应用程序的脆弱性。
缓冲区溢出
服务器上最可怕的攻击类型是远程用户可以执行恶意代码导致系统完全破坏的攻击。大多数此类攻击都是由于缓冲区溢出错误造成的。这种错误的典型示例是:在 C 代码中为某本地变量分配了固定长度,然后该代码将 HTTP 请求中的信息复制到该变量中。如果您认为请求中的数据不会比您设定的值大,而对您的服务器的恶意请求可以超过该值,并导致其发送的数据在写入到已分配的缓冲区时超出末端。对于本地变量,缓冲区存储在堆栈中,而堆栈中还存储了当前函数结束时要返回的代码地址。通过写入时超出本地变量缓冲区的末端,黑客可以覆盖返回地址并使函数返回到他想要的任何地址,包括 Windows CreateProcess 函数的地址。要传递到 CreateProcess 函数的参数也会存储在堆栈上,如果黑客覆盖了存储这些参数的位置,则可以有效启动服务器上他们想要启动的任何应用程序。
要避免这类攻击,请不要对从请求中读取的数据做任何假设,然后确保缓冲区的处理代码中没有错误。对于 C/C++ 程序员,应对以下函数格外小心:strcpy、strcat、memcpy、gets、sprintf、scanf 以及所有这些函数的变体(如 lstrcpy、wcscpy、CopyMemory 等等)。请注意 strncpy 函数及其他“n”函数只是略好一些,因为在这些方案中长度变量常常是由程序决定的,而且仍有可能覆盖固定长度的缓冲区。“n”函数中的长度参数应根据输出缓冲区的大小而定,而非传入字符串的大小。如果要使用这些函数,请使用“n”版本并从堆中动态分配您的缓冲区以避免可能的堆栈溢出。另外,Microsoft® Visual Studio® .NET C 编译器支持新的 /GS 开关,该开关可使代码不会出现许多常见的缓冲区溢出问题。
利用 .NET 框架和管理代码,可以消除大多数潜在的缓冲区溢出问题。Microsoft 设计 .NET 框架时,意识到了垃圾回收的好处,以及如何消除由传统的缓冲区处理方式引起的问题,所以他们提供了管理代码的能力。必须注意管理代码和非管理代码间的交互问题。但是至少可以在您需要时适当保证应用程序的安全。
检查错误
检查所有调用函数的返回代码。如果正在调用 Win32 API,请确保调用已成功完成。如果正在分配内存,请确保未返回 NULL 值。如果正在进行 COM 调用,特别是正在使用 Microsoft® Visual Basic® 进行调用并且已指定“On Error Resume Next”语句,请确保未出现异常。同样,不要对这类调用的结果做任何假设。
如果正在调用 Win32 安全函数,应特别小心。例如,如果正在调用 ImpersonateLoggedOnUser,应检查返回代码是否存在错误,否则将难以为用户提供较高的安全环境。当您的 Web 应用程序配置为在 IIS 上以“进程内”方式运行时要格外注意这一点,因为代码可能以本地系统帐户运行,这在本地计算机上几乎没有限制。还应注意某些交叉的 COM 调用同样可能在具有较高权限的线程中运行。
尽早、尽快地验证输入
XML Web 服务接收请求时,您应做的第一件事就是验证提交的数据。根据架构进行 Web 服务说明语言 (WSDL) 验证将会捕获许多错误,但是您应立即执行所需的任何应用程序级的验证。包括检查特殊字符、检查特定范围内的数值、检查字符串长度,等等。即使认为所有请求必须来自特定的应用程序,也应在进行证明之前假定传入数据是无效的。事实是对 XML Web 服务的请求可以来自任何地方。如果对数据进行假设,应假定数据可能来自某个恶意用户。
参数验证代码能够快速地完成也是很重要的。识别无效请求的速度越快越好。否则 XML Web 服务容易遭受拒绝服务攻击。如果您的服务器处理非法请求的时间较长,则很可能不能为合法请求提供服务。始终应用与专用数据同等的安全级别来对待消耗时间和资源的操作。如果必须执行耗时的 SQL 查询,或者某个操作要求具有很强的处理能力,则首先要确保请求的合法性。用户是否是合法用户?对请求进行身份验证不仅能防止无效用户使用您服务器上的资源,并且提供了跟踪审核日志中的错误使用情况的能力,使您可以发现特定用户非法使用资源的情况。如果正在验证输入,应首先验证用户的凭据。如果使用普通 HTTP 身份验证机制,则在代码调用之前就会为您进行用户身份验证。