参考: The Web Application Hacker’s Handbook Chapter 8
Attacking Access Controls
在应用程序的核心安全机制内,访问控制在逻辑上建立在身份验证和会话管理之上。 到目前为止,您已经了解了应用程序如何首先验证用户的身份,然后确认它接收到的特定请求序列是来自同一用户的。 应用程序需要执行这些操作的主要原因(至少就安全性而言)是因为它需要一种方法来决定是应允许给定请求执行其尝试的操作还是访问其所请求的资源。 访问控制是应用程序中的关键防御机制,因为它们负责做出这些关键决策。 当它们有缺陷时,攻击者通常可以破坏整个应用程序,控制管理功能并访问属于每个其他用户的敏感数据。
如第1章所述,访问控制中断是Web应用程序漏洞中最常遇到的类别之一,影响了作者最近测试的71%的应用程序。 遇到应用程序时会遇到麻烦,因为它们会麻烦地实施用于身份验证和会话管理的强大机制,而忽略了在应用程序上建立有效的访问控制,从而浪费了这些投资。 这些弱点如此普遍的一个原因是,需要在特定时间针对特定用户尝试执行的资源上的每个请求和每个操作执行访问控制检查。 与许多其他控制类别不同,这是需要人工完成的设计决策。 它不能通过采用技术来解决。
访问控制漏洞从概念上讲很简单:该应用程序可让您执行您不应该做的事情。 各个缺陷之间的差异实际上归结为体现此核心缺陷的方式不同,以及检测该缺陷所需要采用的不同技术。 本章介绍所有这些技术,展示如何在应用程序中利用各种行为来执行未经授权的操作并访问受保护的数据。
Common Vulnerabilities
访问控制可以分为三大类:垂直,水平和上下文相关。
垂直访问控件允许不同类型的用户访问应用程序功能的不同部分。 在最简单的情况下,这通常涉及普通用户和管理员之间的区分。 在更复杂的情况下,垂直访问控制可能涉及授予特定功能访问权限的细粒度用户角色,每个用户被分配给单个角色或不同角色的组合。
水平访问控制允许用户访问相同类型的更广泛资源的某个子集。 例如,一个Web邮件应用程序可能允许您阅读您的电子邮件,但没有其他人可以阅读,一个在线银行可以让您仅从您的帐户中转帐资金,而一个工作流应用程序则可以让您更新分配给您的任务,但是 仅读取分配给其他人的任务。
上下文相关的访问控制可确保在给定当前应用程序状态的情况下,用户的访问限于所允许的范围。 例如,如果用户正在跟踪一个过程中的多个阶段,则上下文相关的访问控制可能会阻止用户访问超出规定顺序的阶段。
在许多情况下,垂直和水平访问控制是交织在一起的。 例如,企业资源计划应用程序可以允许每个应付帐款业务员支付特定组织单位的发票,而不能支付其他任何发票。 另一方面,应付帐款经理可以被允许支付任何单位的发票。 同样,文员可以支付少量发票,但较大的发票必须由经理支付。 财务主管可能能够查看公司中每个组织单位的发票付款和收据,但可能不允许其支付任何发票。
如果任何用户可以访问未经其授权的功能或资源,则访问控制将被破坏。 针对访问控制的攻击主要分为三种类型,分别对应三种控制类型:
- 当用户可以执行其分配的角色不允许他执行的功能时,就会发生垂直特权升级。 例如,如果普通用户可以执行管理功能,或者业务员可以支付任何大小的发票,则访问控制将被破坏。
- 当用户可以查看或修改其无权使用的资源时,就会发生横向特权升级。 例如,如果您可以使用Web邮件应用程序阅读其他人的电子邮件,或者如果付款员可以处理非他单位的组织单位的发票,则访问控制将被破坏。
- 当用户可以利用应用程序状态机中的漏洞来获取对关键资源的访问权时,就会发生业务逻辑利用。 例如,用户可能能够在购物结帐序列中绕过支付步骤。
在常见的情况下,应用程序水平特权分离中的漏洞会立即导致垂直升级攻击。 例如,如果用户找到一种设置其他用户密码的方法,则该用户可以攻击管理帐户并控制该应用程序。
在到目前为止描述的情况下,损坏的访问控制使已在特定用户上下文中向应用程序进行身份验证的用户可以执行操作或访问该上下文对其未授权的数据。 但是,在最严重的访问控制中断的情况下,完全未经授权的用户可能会获得对旨在仅由特权认证用户访问的功能或数据的访问。
1.完全不受保护的功能(Completely Unprotected Functionality)
在访问控制中断的许多情况下,任何知道相关URL的人都可以访问敏感的功能和资源。 例如,在许多应用程序中,访问特定URL的任何人都可以充分利用其管理功能:
https://wahh-app.com/admin/
在这种情况下,应用程序通常仅在以下范围内实施访问控制:以管理员身份登录的用户在其用户界面上看到指向该URL的链接,而其他用户则没有。 这种外观上的差异是“保护”敏感功能不受未经授权使用的唯一机制。
有时,授予对强大功能的访问权限的URL可能不那么容易猜测,甚至可能非常隐秘:
https://wahh-app.com/menus/secure/ff457/DoAdminMenu2.jsp
在这里,假设攻击者不会知道或发现此URL,则可以保护对管理功能的访问。 局外人很难妥协该应用程序,因为他不太可能猜测自己可以使用的URL。
在某些应用程序中,敏感功能隐藏在不容易猜测的URL后面,攻击者通常可以通过仔细检查客户端代码来识别这些功能。 许多应用程序使用JavaScript在客户端内部动态构建用户界面。 通常,这可以通过设置有关用户状态的各种标志,然后基于以下标志将各个元素添加到UI来实现:
var isAdmin = false;
...
if (isAdmin)
{
adminMenu.addItem(“/menus/secure/ff457/addNewPortalUser2.jsp”,“create a new user”);
}
在这里,攻击者可以简单地查看JavaScript以识别用于管理功能的URL并尝试访问它们。 在其他情况下,HTML注释可能包含对未从屏幕内容链接的URL的引用或线索。 第4章讨论了攻击者可以用来收集有关应用程序中隐藏内容的信息的各种技术。
1.1 直接访问方法(Direct Access to Methods)
当应用程序公开实际上是API方法的远程调用的URL或参数时,通常会出现未受保护的功能,通常是Java接口公开的URL或参数。 当服务器端代码移至浏览器扩展组件并创建方法存根时,通常会发生这种情况,以便代码仍可以调用其运行所需的服务器端方法。 在这种情况之外,可以确定某些直接访问方法的实例,其中URL或参数使用标准Java命名约定,例如getBalance
和isExpired
。
原则上,指定要执行的服务器端API的请求与指定服务器端脚本或其他资源的请求一样安全。 但是,实际上,这种类型的机制经常包含漏洞。 通常,客户端直接与服务器端API方法进行交互,并绕过应用程序对访问或意外输入向量的常规控制。 还存在其他功能可以通过这种方式调用,并且不受任何控件保护的可能性,前提是该功能永远不会被Web应用程序客户端直接调用。 通常,需要为用户提供对某些特定方法的访问权限,但是却为他们提供了对所有方法的访问权限。 这是由于开发人员没有完全了解要代理的方法的子集并提供对所有方法的访问,或者是由于默认情况下用于将它们映射到HTTP服务器的API提供了对所有方法的访问。
以下示例显示了从接口securityCheck
内调用的getCurrentUserRoles
方法。
http://wahh-app.com/public/securityCheck/getCurrentUserRoles
在此示例中,除了测试对getCurrentUserRoles
方法的访问控制之外,还应该检查是否存在其他类似命名的方法,例如getAllUserRoles
,getAllRoles
,getAllUsers
和getCurrentUserPermissions
。 本章稍后将介绍针对测试直接访问方法的进一步考虑。
2.基于标识符的功能(Identifier-Based Functions)
当使用应用程序的功能来访问特定资源时,通常会在URL查询字符串或POST正文中的请求参数中看到将请求资源传递给服务器的标识符 请求。 例如,应用程序可以使用以下URL来显示属于特定用户的特定文档:
https://wahh-app.com/ViewDocument.php?docid=1280149120
拥有文档的用户登录后,该URL的链接将显示在用户的“我的文档”页面上。 其他用户看不到该链接。 但是,如果访问控制被破坏,则任何请求相关URL的用户都可以以与授权用户完全相同的方式查看文档。
TIP 当主应用程序与外部系统或后端组件交互时,通常会出现这种类型的漏洞。 在可能基于各种技术的不同系统之间共享基于会话的安全模型可能很困难。 面对此问题,开发人员经常使用客户端提交的参数来做出访问控制决策的捷径并远离该模型。
在此示例中,试图获得未经授权的访问的攻击者不仅需要知道应用程序页面的名称(ViewDocument.php),还需要知道他想要查看的文档的标识。有时,资源标识符的生成方式非常不可预测。例如,它们可以是随机选择的GUID。在其他情况下,它们可能很容易猜到;例如,它们可以是顺序生成的数字。但是,在两种情况下该应用程序都容易受到攻击。如前所述,URL没有机密状态,资源标识符也是如此。通常,想要发现其他用户资源标识的攻击者可以在应用程序中找到公开这些资源的位置,例如访问日志。即使无法轻易猜出应用程序的资源标识,但如果应用程序无法正确控制对这些资源的访问,它仍然容易受到攻击。在容易预测标识符的情况下,该问题更加严重,也更容易利用。
TIP 应用程序日志通常是信息的金矿。 它们可能包含大量数据项,这些数据项可用作标识符,以探测以此方式访问的功能。 在应用程序日志中通常可以找到的标识符包括用户名,用户ID号,帐号,文档ID,用户组和角色以及电子邮件地址。
NOTE 除了用作对应用程序中基于数据的资源的引用之外,这种标识符还经常用于引用应用程序本身的功能。 如在第4章中所见,应用程序可以通过一个页面来交付不同的功能,该页面接受一个函数名或标识符作为参数。 再次在这种情况下,访问控制的运行范围可能不超过不同类型用户界面中是否存在特定URL。 如果攻击者可以确定敏感功能的标识符,则他可能能够以与特权用户相同的方式来访问它。
3.多级功能(Multistage Functions)
应用程序中的多种功能是跨多个阶段实现的,涉及从客户端向服务器发送多个请求。 例如,添加新用户的功能可能涉及从用户维护菜单中选择此选项,从下拉列表中选择部门和用户角色,然后输入新的用户名,初始密码和其他信息。
经常遇到这样的应用程序,在这些应用程序中已尽力保护这种敏感功能不受未经授权的访问,但是由于对功能使用方式的假设存在缺陷,因此所采用的访问控制被破坏了。
在前面的示例中,当用户尝试加载用户维护菜单并选择添加新用户的选项时,应用程序可以验证该用户具有所需的特权,如果没有,则阻止访问。 但是,如果攻击者直接进入指定用户部门和其他详细信息的阶段,则可能没有有效的访问控制。 开发人员无意识地认为到达过程后期的任何用户都必须具有相关特权,因为该特权已在早期阶段进行了验证。 结果是该应用程序的任何用户都可以添加新的管理用户帐户,从而完全控制该应用程序,从而可以访问其访问控制本质上很强大的许多其他功能。
即使在最安全关键的Web应用程序(由在线银行部署的Web应用程序)中,作者也遇到了此类漏洞。在银行应用程序中进行资金转帐通常涉及多个阶段,部分是为了防止用户在请求转帐时意外地犯错。这个多阶段过程涉及在每个阶段从用户捕获不同的数据项。首次提交时会彻底检查该数据,然后通常使用HTML格式的隐藏字段将其传递到每个后续阶段。但是,如果应用程序在最终阶段没有重新验证所有这些数据,则攻击者可能会绕过服务器的检查。例如,应用程序可能会验证为转移选择的源帐户是否属于当前用户,然后询问有关目标帐户和转移量的详细信息。如果用户拦截了此过程的最终POST请求并修改了源帐号,则她可以执行横向特权上报,并从属于其他用户的帐户中转出资金。
Chapter 7 Attacking Session Management(4)-Securing Session Management
Chapter 8 Attacking Access Controls-Common Vulnerabilities(2)