(OWASP汉化)攻击系列大全(六十八):Xpath注入攻击

最新版本:(mm/dd/yy): 04/15/2015
翻译至XPATH Injection

概述

SQL注入类似,当网站使用用户提供的信息为XML数据构建XPath查询时,会发生XPath注入攻击。通过向网站发送故意的畸形信息,攻击者可以找出XML数据的结构或访问他通常无法访问的数据。如果使用XML数据进行身份验证(例如基于XML的用户文件),他甚至可以提升其在Web站点上的权限。

查询XML是用XPath完成的,XPath是一种简单的描述性语句,它允许XML查询定位一条信息。像SQL一样,您可以指定要查找的特定属性以及匹配的模式。当在web站点上使用XML时,通常会接受所输入的查询字符串的某种形式,来识别在页面上定位和显示的内容。必须对此输入进行消毒,以验证它不会混淆XPath查询并返回错误的数据。

XPath是一种标准语言;它的符号/语法总是独立执行的,这意味着攻击可能是自动的。在对SQL数据库的请求中,没有不同的方言。

由于没有级别访问控制,因此可以获取整个文档。我们不会遇到任何限制,因为我们可能从SQL注入攻击中知道。

漏洞实例

我们将使用这段XML作为例子

<?xml version="1.0" encoding="utf-8"?>
<Employees>
   <Employee ID="1">
      <FirstName>Arnold</FirstName>
      <LastName>Baker</LastName>
      <UserName>ABaker</UserName>
      <Password>SoSecret</Password>
      <Type>Admin</Type>
   </Employee>
   <Employee ID="2">
      <FirstName>Peter</FirstName>
      <LastName>Pan</LastName>
      <UserName>PPan</UserName>
      <Password>NotTelling</Password>
      <Type>User</Type>
   </Employee>
</Employees>

假设我们在使用这种数据文件的网页上有一个用户认证系统来登录用户。一旦提供用户名和密码,软件可能会使用XPath查找用户:

VB:
Dim FindUserXPath as String
FindUserXPath = "//Employee[UserName/text()='" &amp; Request("Username") &amp; "' And 
        Password/text()='" &amp; Request("Password") &amp; "']"

C#:
String FindUserXPath;
FindUserXPath = "//Employee[UserName/text()='" + Request("Username") + "' And 
        Password/text()='" + Request("Password") + "']";

使用正常的用户名和密码,XPath可以工作,但是攻击者可能会发送错误的用户名和密码,并在不知道用户名或密码的情况下选择XML节点,如下所示:

Username: blah' or 1=1 or 'a'='a
Password: blah

FindUserXPath becomes //Employee[UserName/text()='blah' or 1=1 or 
        'a'='a' And Password/text()='blah']

Logically this is equivalent to:
        //Employee[(UserName/text()='blah' or 1=1) or 
        ('a'='a' And Password/text()='blah')]

在这种情况下,只要XPath的第一部分需要为真。密码部分就变得不相关,并且由于“1 = 1”部分,UserName部分将匹配所有员工。

XPath注入防御

就像避免SQL注入的技术一样,您需要使用参数化的XPath接口(如果有的话),或者避开用户输入,使其安全地包含在动态构建的查询中。如果您使用引号在动态构造的XPath查询中终止不可信的输入,那么您需要在不受信任的输入中避免引用,以确保不受信任的数据不能跳出引用的上下文。在下面的示例中,使用单引号(')来终止用户名和密码参数。因此,我们需要替换所有输入中的字符。

VB:
Dim FindUserXPath as String
FindUserXPath = "//Employee[UserName/text()='" &amp; Request("Username").Replace("'", "&apos;") &amp; "' And 
        Password/text()='" &amp; Request("Password").Replace("'", "&apos;") &amp; "']"

C#:
String FindUserXPath;
FindUserXPath = "//Employee[UserName/text()='" + Request("Username").Replace("'", "&apos;") + "' And 
        Password/text()='" + Request("Password").Replace("'", "&apos;") + "']";

另一个更好的缓解方法是使用预编译的XPath[1]查询。预编译的XPath查询在程序执行之前已经预先设置好了,而不是在用户的输入被添加到字符串之后创建的。这是一个更好的方法,因为您不必担心丢失一个应该被转义的字符。

相关的威胁代理

相关攻击

相关漏洞

相关控件

就像SQL注入一样,为了保护自己,如果您的应用程序使用它们,您必须转义单引号(或双引号)。

VB:

Dim FindUserXPath as String
FindUserXPath = "//Employee[UserName/text()='" &
Request("Username").Replace("'", "'") & "' And
       Password/text()='" & Request("Password").Replace("'", "'") & "']"

C#:

String FindUserXPath;
FindUserXPath = "//Employee[UserName/text()='" +
Request("Username").Replace("'", "'") + "' And
       Password/text()='" + Request("Password").Replace("'", "'") + "']";

另一个更好的缓解选项是使用预编译的XPath 。预编译的XPath在程序执行之前就已经预先设置好了,而不是在用户的输入被添加到字符串之后实时创建的。这是一条更好的路线,因为您不必担心错过本应该逃跑的角色。

使用参数化的XPath查询 – 参数化会导致输入被限制在特定的域(如字符串或整数),并且这些域之外的任何输入被视为无效,并且查询失败。

使用自定义错误页面 – 攻击者可以从描述性错误消息中收集有关查询性质的信息。输入验证必须与定制的错误页面结合起来,以通知错误而不披露关于数据库或应用程序的信息。