除了在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进行从后端服务通信到数据存续的所有工作,我们比以往都更需要保持对这些方法造成的威胁和风险的警惕。