17.1 分层架构

许多Web应用程序使用多层架构,在这个架构中,应用程序用户界面、业务逻辑与数据存储分别位于不同的层次中,这些层次可能采用各种技术,并在不同的计算机上运行。一个常用的三层架构可分为以下层次:

img002 展现层,执行应用程序的界面;

img002 应用程序层,执行核心应用程序逻辑;

img002 数据库层,存储并处理应用程序数据。

实际上,许多复杂的企业应用程序对不同层次进行更详细的划分。例如,一个基于 Java 的应用程序可能采用以下层次与技术:

img002 应用程序服务器层(例如Tomcat);

img002 展现层(例如WebWork);

img002 授权与验证层(例如JAAS或ACEGI);

img002 核心应用程序框架(例如Struts或Spring);

img002 业务逻辑层(例如Enterprise Java Beans);

img002 数据库对象关系映射(例如Hibernate);

img002 数据库JDBC调用 ;

img002 数据库服务器。

与单层设计相比,多层架构具有诸多优点。与大多数软件设计方法一样,将高度复杂的处理任务分解成简单、模块化的功能组件,能够显著改善应用程序开发管理并降低漏洞的发生率。拥有明确定义界面的独立组件可在不同的应用程序内及应用程序之间重复使用。不同的开发者可以并行开发不同的组件,而不必深入了解其他组件的执行细节。如果有必要替换一个层次使用的技术,替换过程也不会给其他层次造成严重影响。另外,如果运用合理,多层架构可显著改善整个应用程序的安全状态。

17.1.1 攻击分层架构

前面的分析结果表明,如果一个多层架构的执行过程存在缺陷,这些缺陷可能会引入安全漏洞。了解多层模型可帮助渗透测试员确定实施各种安全防御(如访问控制与输入确认)的位置,以及如何穿越层次边界来破坏这些防御,从而对Web应用程序实施有效攻击。设计不佳的分层架构可能受到以下3种类型的攻击。

img002 可以利用不同层之间的信任关系扩大攻击范围,从一个层侵入到另一个层。

img002 如果不同层之间没有完全隔离,就可以利用某一层存在的缺陷直接破坏另一层实施的安全保护。

img002 局部攻破一个层后,就可以直接攻击其他层的基础架构,从而将攻击扩大到其他层。

下面逐一详细介绍这些攻击。

1.利用层之间的信任关系

应用程序的不同层之间彼此信任,并以特殊的方式运转。如果应用程序运行正常,这些假设就有效。然而,在反常情况下或者应用程序正受到攻击时,上述假设就会被打破。这时渗透测试员就可以利用这些信任关系将攻击范围由一个层扩大到另一个层,增加安全违反的严重程度。

许多企业应用程序中存在一种十分常见的信任关系,即某个应用程序层专门负责管理用户访问。这个层实施验证与会话管理,并执行各种逻辑,决定是否准予某个特殊的请求。如果该应用程序层决定准予一个请求,它就向其他层发出相关命令,以执行被请求的操作。其他层相信准予请求的应用程序层,认为它已经实施了严格的访问控制检查,因而执行它们从该应用程序层收到的全部命令。

这种类型的信任关系会加速恶化我们在前面章节中讨论的许多常见的Web漏洞。如果应用程序中存在 SQL 注入漏洞,攻击者就可以利用它访问应用程序中的所有数据。即使应用程序并不以数据库管理员的身份访问数据库,它通常也会使用一个能够读取并更新所有应用程序数据的独立账户。因此,数据库层完全信任对它的数据实施访问控制的应用程序层。

同样,应用程序组件通常使用较高权限的操作系统账户运行,这些账户能够执行敏感操作并访问关键文件。在这种配置下,操作系统层完全信任相关应用程序层,认为它不会执行有害操作。如果攻击者发现一个命令注入漏洞,在利用它攻破应用程序层后,他们还可以进一步完全攻破为应用程序层提供支持的基础操作系统。

层之间的信任关系还可能导致其他问题。如果一个应用程序层存在编程错误,那么这些错误可能会导致其他层出现反常行为。例如,第 11 章描述的竞态条件导致后端数据库提供属于错误用户的账户信息。而且,如果管理员正在调查一起意外事件或安全违反行为,只通过查阅信任层中的审计日志通常并不足以帮助他们完全了解事件的整个发生过程,因为他们只能确定可信层是引发事件的媒介。例如,发生 SQL 注入攻击后,数据库日志可能会记录攻击者注入的每一个查询,但要确定哪一名用户是攻击者,还必须将这些事件与应用程序层中的日志记录进行交叉参考,因为通过日志记录无法确定攻击者。

2.破坏其他层

如果应用程序的不同层之间没有完全隔离,那么攻破一个层的攻击者就可以直接破坏另一个层实施的安全保护,从而执行这个层负责控制的操作或访问其中的数据。

如果几个层在相同的计算机上执行,那么这时往往会出现漏洞。为节省成本,许多应用程序常常采用这种架构配置。

img007 访问解密算法

通常,为满足PCI等管理或法规要求,许多应用程序都会对敏感的用户数据进行加密,以最大限度地降低应用程序被攻破造成的影响。虽然可以对密码进行“加salt散列”处理,以确保即使数据存储被攻破,攻击者仍然无法确定密码,但对于应用程序需要将其恢复为明文值的数据,则需要采用不同的处理方法。关于这类数据,最常见的示例包括用户的安全问题(可以通过与服务台进行交互来确认)和支付卡信息(在付款时需要这些信息)。为此,需要采用某种双向加密算法。使用加密时出现的典型漏洞是:加密密钥与加密数据之间未进行逻辑隔离。在现有环境中使用加密时,一种简单但存在缺陷的隔离方法,是将算法和相关密钥置于数据层,以避免影响到其他代码。但是,如果数据层也被攻破(例如,通过SQL注入攻击),攻击者将可以轻松确定并执行解密功能。

img001  注解  无论以何种方法进行加密,只要应用程序能够解密信息,并且应用程序被完全攻破,攻击者总是能够确定解密算法的逻辑路径。

img007 使用文件读取访问权限提取MySQL数据

许多小型应用程序使用一个LAMP服务器(运行Linux、Apache、MySQL 和 PHP 等开源软件的独立计算机)。在这种架构中,如果Web应用程序层中的一个文件泄露漏洞,其本身并不会造成严重的缺陷,但却可以导致攻击者无限制地访问应用程序的所有数据,因为MySQL数据保存在可读的文件中,且Web应用程序进程通常有权读取这些文件。即使数据库对它的数据实施了严格的访问控制,而且应用程序使用一系列低权限的账户连接数据库,但如果攻击者能够直接访问保存在数据库层中的数据,他仍然可以完全避开这些保护。

例如,图17-1所示的应用程序允许用户选择一种皮肤,自定义他们的使用体验。这要求用户选择一个层叠样式表(Cascading Style Sheet,CSS)文件,并且应用程序会将这个文件呈现给用户审查。

img503a

图17-1 一个包含查看选中文件功能的应用程序

如果这个功能包含一个路径遍历漏洞(请参阅第10章了解相关内容),那么攻击者就可以利用这个漏洞直接访问保存在MySQL数据库中的任意数据,从而破坏在数据库层实施的访问控制。图17-2显示了一个从MySQL用户表中成功获取用户名和密码散列的攻击。

img503b

图17-2 一个破坏数据库层,获取任意数据的攻击

img004  提示  如果攻击者具有文件写入访问权限,就可以尝试对应用程序的配置或托管的虚拟目录执行写入操作,以执行相关命令。请参阅第10章的nslookup示例。

img007 使用本地文件包含执行命令

许多语言都包含用于在当前脚本中包含本地文件的函数。如果攻击者能够指定文件系统上的任何文件,这无疑是一个严重的问题。此类文件可能为/etc/passwd文件或包含密码的配置文件。很明显,这些情况会导致信息披露,但攻击者不一定能够扩大攻击范围,以进一步攻破整个系统(如第10章所述,通过远程文件包含无法达到这一目的)。不过,攻击者仍然可以利用其他应用程序或平台功能,通过包含一个内容部分受其控制的文件来执行命令。

例如,某应用程序在以下URL的country参数中提交用户输入:

http://eis/mdsecportal/prefs/preference_2?country=en-gb

用户可以修改country参数来包含任意文件。一个可能的攻击是,请求包含脚本命令的URL,以便将这些命令写入Web服务器日志文件,然后使用本地文件包含行为包含这个日志文件。

一种利用PHP体系架构怪癖的有趣方法,是以明文形式将PHP会话变量写入使用会话令牌命名的文件中。例如,以下文件:

/var/lib/php5/sess_9ceed0645151b31a494f4e52dabd0ed7

可能包含下列内容,其中包含用户配置的昵称:

img504a

攻击者可以对这种行为加以利用。首先,他将自己的昵称设置为<?php passthru(id);?>,如图17-3所示。然后,他包含会话文件,使用以下URL执行id命令,如图17-4所示。

img504c

图17-3 配置包含服务器可执行的脚本代码的昵称

img505

图17-4 通过本地文件包含功能执行包含恶意昵称的会话文件

img504b