本文主要介绍代码注入攻击的一种特殊类型:XPath 盲注。
如果您不熟悉 XPath 1.0 或需要了解基础知识,请查看 W3 Schools XPath 教程。您还可以在 developerWorks 上找到大量的关于在各种语言环境中使用 XPath 的文章。本文使用的示例主要针对 XPath 1.0,但是也可用于 XPath 2.0。XPath 2.0 实际上增加了您可能遇到的问题。
本文还提供了用于处理 Java JDK 5.0 的 Java 代码示例。同时本文的概念和主题是跨平台的,如果您的应用程序使用 XPath 获取特殊的代码示例,那么您必须使用 JDK 5.0。
代码注入
一种更常见的对 Web 应用程序的攻击和威胁是某种形式的代码注入,Wikipedia 将其定义为:利用系统没有对其输入进行强制执行或检查的假设向计算机系统中引入(或 “注入”)代码的技术。
注入代码的目的通常是绕过或修改程序的最初目标功能。如果被绕过的功能涉及系统安全,那么结果可能是灾难性的。
快速浏览任何相关 Web 站点(比如 Web Application Security Consortium 或 Security Focus)都会显示很多使用某种形式的代码注入进行的攻击,从 JavaScript 到 SQL 注入再到其他形式的代码注入攻击。最近开始出现的一种威胁是 XPath 盲注攻击。这种攻击的运作跟 SQL 盲注攻击几乎完全相似,与 SQL 注入攻击不同的是,几乎没什么人了解 XPath 盲注攻击或对其进行预防。与 SQL 注入攻击类似,如果使用最佳实践开发安全的应用程序,通常可以轻松地处理该威胁。
XPath 攻击
一般说来,大多数 Web 应用程序使用关系数据库存储和检索信息。
例如,如果您的 Web 站点需要身份验证,那么您可能拥有一个 users 表,其中包含惟一 ID、登录名、密码,也许还有一些其他信息,比如角色。从 users 表中检索用户的 SQL 查询可能类似于清单 1。
清单 1. 从 users 表中检索用户的 SQL 查询
Select * from users where loginID=’foo’ and password=’bar’
在这个查询中,用户必须提供 loginID 和 password 作为输入。
如果攻击者在 loginID 字段中输入:’ or 1=1
则形成的查询将类似清单 2。并在 password 中输入:’ or 1=1
清单 2. 从攻击者输入形成的查询
Select * from users where loginID = ’’ or 1=1 and password=’ ’ or 1=1
这个条件会一直匹配,因此攻击者可以进入系统。
XPath 注入的原理大体类似。但是,假设您拥有的不是一个 users 表,而是一个 XML 文件,其中包含了如清单 3 所示的用户信息。
清单 3. user.xml
<?xml version="1.0" encoding="UTF-8"?>
<users>
<user>
<firstname>Ben</firstname>
<lastname>Elmore</lastname>
<loginID>abc</loginID>
<password>test123</password>
</user>
<user>
<firstname>Shlomy</firstname>
<lastname>Gantz</lastname>
<loginID>xyz</loginID>
<password>123test</password>
</user>
<user>
<firstname>Jeghis</firstname>
<lastname>Katz</lastname>
<loginID>mrj</loginID>
<password>jk2468</password>
</user>
<user>
<firstname>Darien</firstname>
<lastname>Heap</lastname>
<loginID>drano</loginID>
<password>2mne8s</password>
</user>
</users>
在 XPath 中,类似于 SQL 查询的语句如清单 4 所示。
清单 4. 匹配 SQL 查询的 XPath 语句
//users/user[loginID/text()=’abc’ and password/text()=’test123’]
要执行类似的攻击以绕过身份验证,
如果攻击者在 loginID 字段中输入:’ or 1=1
您可能会使用类似清单 5 的方法。并在 password 中输入:’ or 1=1
清单 5. 绕过身份验证
//users/user[LoginID/text()=’’ or 1=1 and password/text()=’’ or 1=1]
您可能在 Java 应用程序中有一个诸如 doLogin 之类的方法,使用清单 3 中的 XML 文档再次执行身份验证。可能类似于清单 6。
清单 6. XPathInjection.java
import java.io.IOException;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import javax.xml.parsers.*;
import javax.xml.xpath.*;
public class XpathInjectionExample {
public boolean doLogin(String loginID, String password)
throws ParserConfigurationException, SAXException,IOException,
XPathExpressionException {
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse("users.xml");
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression expr = xpath.compile("//users/user[loginID/text()=’"+loginID+"’
and password/text()=’"+password+"’ ]/firstname/text()");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
//print first names to the console
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());}
if (nodes.getLength() >= 1) {
return true;
}
else{
return false;
}
}
}
XML注入(XML Injection)
如同HTML脚本注入一样,在输出中包含攻击者提供的数据的地方,XML是容易受到攻击的。三种最常见的XML注入攻击是:XML数据注入、可扩展样式表语言转换(Extensible Stylesheet Language Transformation,XSLT)注入和XPath/XQuery 注入。
·XML数据注入(XML Data Injection)
XML通常用于存储数据,如果用户提供的数据是以XML的方式进行存储,那么对攻击者来说,注入额外的、攻击者可能不能正常控制的XML是有可能的。考虑下述XML,在这个XML中,攻击者仅仅能够控制Attacker Text文本:
<?xmlversion="1.0" encoding="UTF-8"?>
<USER role="guest">Attacker Text</USER>
如果用你的输入来替换Attacker Text,那将会是多么有趣的测试用例呢?如果开发人员不够谨慎的话,他们可能错误地允许XML注入。
如果以User1</USER><USER role=“admin”>User2 作为输入的话,将会产生如下的XML(用户输入的是黑体文本部分):
<?xmlversion="1.0" encoding="UTF-8"?>
<USER role="guest">User1</USER>
<USER role="admin">User2</USER>
如果应用程序读取这个文件,并且决定给每个用户分配何种访问权限的时候,User2将获得管理员权限!
提示 如果你能够在XML文件的某个部分注入数据的话,那么发送相同的元素和属性(这些元素和属性是在以前的XML中出现过的,并且是你所不能访问的)就会很有价值。一些XML解析器会使用最后指定的那些元素/属性的实例,这样,你或许就能够有选择性地覆盖以前的一些值。 |
·可扩展样式表语言(XSL)
除了注入数据到XML之外,作为XML注入的结果,使代码运行也是可能的。XSL由XSL转换(XSL Transform,XSLT)、XML路径语言(XML PathLanguage,XPath)表达式和XSL格式化对象(Formatting Object,XSL-FO)组成,并且允许在XML文件中使用样式表。这种样式表能够把已有的XML数据转换成新的XML数据。这种新的XML文档通常以HTML的方式在Web浏览器中展现。在这种情况下,攻击者能够注入数据,而这些数据将使脚本在浏览器中运行。
例如,下述XML是RSS提要(RSS feed)中的一部分,这个XML引用了一个超链接:
<link>AttackerText</link>
为了表示上述XML,应用XSLT将上述XML转换为如下的HTML,并传送给Web浏览器:
<AHREF="Attacker Text">Attacker Text</A>
如果你控制了Attacker Text文本的话,你能够想到一种方法来运行脚本吗?即使程序员对攻击者提供的文本进行了HTML编码,攻击者仍然能够利用脚本协议,通过类似于javascript:alert()的输入来运行脚本。如果这个HTML在一个站点或者一定的范围内表现得与原始RSS提要(RSS feed)不同的话,那么,这就是一种通过XML数据引发的HTML脚本攻击。
重要提示 当测试XML注入的时候,可以试着发送尖括号和引号标志来转义当前的XML属性/标签。当应用程序被正确保护的时候,它就不会让用户提供数据来转 |
·XPath/XQuery注入
XPath和XQuery是能够查询XML文档的语言,类似于结构化查询语言(SQL)。事实上,许多流行的数据库允许利用XPath和XQuery来查询数据库。在许多情况下,攻击者不能够直接访问XML数据,但是,攻击者可以用部分数据来创建XPath和XQuery语句,而这些语句能够用来查询XML。这样,攻击者就能够通过精心构造的输入来注入任意的查询,以此来获得数据,而这些数据在正常情况下是不允许攻击者访问的。
XML文件能够包括信息的不同部分或者区域。有时,只有这些信息中的特定部分才会被暴露给最终用户,例如,下述XML包含了姓名和社会保障号:
<?xmlversion='1.0'?>
<staff>
<author>
<name>Tom Gallagher</name>
<SSN>123-45-6789</SSN>
</author>
<author>
<name>Bryan Jeffries</name>
<SSN>234-56-7890</SSN>
</author>
<author>
<name>Lawrence Landauer</name>
<SSN>012-345-6789</SSN>
</author>
</staff>
这个XML存储在一个Web服务器上,并且是不能够被最终用户直接访问的。在这个服务器上用于查询XML的一个网页是能够被最终用户访问的,而且,只有作者姓名能够通过网页进行显示。利用下述XPath表达式就能够获得XML数据:
//*[contains(name,'Attacker-Data')]/name
Attacker-Data是最终用户指定的数据,正如你所看到的那样,攻击者能够控制部分XPath查询。通过指定数据为x')] | //*| //*[contains(name,'y,攻击者能够获得这个XML文件的完整内容。这种输入构造了如下的XPath表达式:
//*[contains(name,'x')] | //*| //*[contains(name,'y')]/name
注意在上述表达式中,管道符号(|)用于表示或操作,左斜线和一个星号(//*)代表所有节点。上述XPath表达式可能有下述三种情况:
1.任何包含x的姓名
2.任何在这个XML文件中的节点
3.任何包含y的姓名
因为在第二种情况下能够返回所有节点,所以攻击者能够获得这个XML文件的所有数据!
更多信息 关于XPath注入的更多信息,请参见Amit Klien在 |
提示 用于XPath/XQuery注入的概念同样适用于SQL |