6.4.7 XPATH注入

除了在RDBMS中存储数据以外,Web应用还常常以XML格式存储数据。XPATH是从XML文档中解析和提取数据的查询语言,通过在XPATH查询中注入恶意输入,我们可以修改查询的逻辑。这种攻击被称做XPATH注入。下面的例子演示了使用XPATH查询读取XML文档中特定元素文本的方法:

假设XML文档为:


<?xml version="1.0" encoding="ISO-8859-1"?>
<users>
<admins>
<user>admin</user>
<pass>admin123</pass>
</admins>
<basic>
<user>guest</user>
<pass>guest123</pass>
</basic>
</users>

使用这个文档,执行以下代码:


Set xmlDoc=CreateObject("Microsoft.XMLDOM")
xmlDoc.async="false"
xmlDoc.load("users.xml")
xmlobject.selectNodes("/users/admins/pass/text()")

/users/admins/pass的查询结果是admin123。

了解了这些,攻击者可以采用无效的输入滥用XPATH查询。和SQL注入不同,使用XPATH时无法注释掉查询的一部分。因此,攻击者必须将附加的逻辑注入到查询中,导致它在可能返回假的时候返回真,或者返回附加的数据。用XPATH注入绕过验证的一个危险的例子基于如下的代码:


String(//users/admins/[user/text()=' " + txtUser.Text + " '
and pass/text()=' "+ txtPass.Text +" '])

如果输入是admin'or 1=1 or'a'='b',查询将如下所示:


String(//users/admins/[user/text()='admin' or 1=1 or 'a'='b'
and pass/text()=''])

表达式


user='admin' or 1=1 or 'a'='b' and pass/text()=' '

可以表示为


(A OR B) OR (C AND D)

逻辑操作符AND的优先级高于OR,所以如果A或者B为真,表达式不管(C AND D)返回的是什么都为真。如果查询的用户输入B是1=1(永远为真),就使得(A OR B)的结果为真。因此查询返回真,攻击者可以登录——用XPATH注入绕过验证机制。

XPath注入对策

和SQL注入类似,XPath注入可以采用适当的输入校验和参数化查询预防。不管是什么应用、环境或者语言,你都应该遵循如下的最佳实践:

·将所有输入都看做不可信任的,尤其是用户的输入,甚至来自于你的数据库或者支持基础架构的输入。

·校验的不仅是数据类型,还有格式、长度、范围和类型(例如,简单的正则表达式如(/^"*^';&<>()/)能够找到可疑的特殊字符)。

·在客户端和服务器都校验数据,因为客户校验很容易回避。

·在发行应用之前针对已知的威胁进行测试。

和数据库服务器不同,XPath不支持参数化的概念。但是,参数化可以用XQuery之类的API模拟。XPath查询可以存储在外部文件中进行参数化:


declare variable $user as xs:string external;
declare variable $pass as xs:string external;//users/user[@user=
$user and @password=$pass]

XQuery代码如下所示:


Document doc = new Builder().build("users.xml");
XQuery xquery = new XQueryFactory().createXQuery(new File("dologin.xq"));
Map vars = new HashMap();
vars.put("user", "admin");
vars.put("pass", "admin123");
Nodes results = xquery.execute(doc, null, vars).toNodes();
for (int i=0; i < results.size(); i++) {
    System.out.println(results.get(i).toXML());
}

XQuery将填充如下XPath代码:


"//users/admins/[user/text()=' " + user + " ' and pass/text()=' "+ pass +" ']"

这种技术提供了稳固的保护,但是没有内建于XPath规范。形成查询时没有直接使用用户输入,而是计算XML文档中的元素值,如果与参数化值不匹配,查询就会失败。通过容易遭到XPath注入攻击的应用,有可能提取整个XML文档。随着Ajax之类的技术和FLEX或者Silverlight等RIA平台的普及,以及来自Google等组织的XML服务的采用,这些技术和服务都高度依赖XML进行从后端服务通信到数据存续的所有工作,我们比以往都更需要保持对这些方法造成的威胁和风险的警惕。