本系列文章主旨在于介绍一些漏洞类型产生的基本原理,探索最基础的解决问题的措施,不排除有些语言或者系统提供的安全的API可以更好地更直接地解决问题,也不排除可以严格地输入验证来解决。
XPath即XML路径语言(XML Path Language),是一种用来确定XML文档中某部分位置的语言。XPath基于XML的树状结构,提供在数据结构树中寻找节点的能力。XPath提出的初衷是将其作为一个通用的、介于XPointer与XSL之间的语法模型。
- XPath使用路径表达式在 XML 文档中进行导航。
- XPath包含一个标准函数库。
- XPath是XSLT中的主要元素。
- XPath是一个W3C标准。
最常见的XPath表达式是路径表达式(XPath这一名称的另一来源)。路径表达式是从一个XML节点(当前的上下文节点)到另一个节点或一组节点的书面步骤顺序。这些步骤以“/”字符分开,每一步由3个成分构成:
- 轴描述(用最直接的方式接近目标节点)
- 节点测试(用于筛选节点位置和名称)
- 节点描述(用于筛选节点的属性和子节点特征)
XPath 1.0定义了4种数据类型:节点型(本身无序的节点组)、字符串型、数字型与布尔型。有效的运算符如下:
- /、//以及..运算符,一般用于轴描述。
- 合集运算符 | 把两个节点形成联集。
- 布尔运算符 and、or以及not()函数。
- 数学运算符+、-、*、div(除)以及mod(取余数)。
- 比较操作子 =、!=(不等于)、<、>、<=、>=。
在XPath查询语言时,也存在注入问题,主要是查询语法中使用的一些特殊字符有特殊的意义,字符以及特殊意义如下:
字 符 | 描 述 | 例 子 |
/ | 用“/”开始的路径代表元素的绝对路径 | /Employees/Employee表示选择元素Employees中的所有Employee元素 |
不用“/”开始的路径代表元素的相对路径 | Employee/FirstName 表示当前路径下的所有的Employee的FirstName | |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置 | // Employee代表所有的Employee元素 |
. | 表示当前节点 | |
.. | 表示当前节点的父节点 | //Type[name(..)='Employee'] 表示选择Type元素,并且Type的父元素是Employee |
* | 可用于选择未知XML元素 | /Employees/Employee /*表示元素Employee中的所有Employee元素的子元素 |
/ Employees /*/ FirstName表示元素order下所有孙子辈节点的FirstName元素 | ||
[] | 指定特定的元素 | / Employees / Employee [1] 表示元素Employees中的第一个Employee的子元素 |
/ Employees / Employee [last()]表示元素Employees中的最后一个Employee的子元素 | ||
| | 在XPath表达式中,使用“|”运算符可以选择几个路径 | // FirstName | // LastName表示从文档中选择所有FirstName和LastName元素 |
/Employees /Employee /FirstName | / Employees /Employee /LastName 表示选择Employees /Employee路径下的FirstName和LastName | ||
@ | 选取属性 | //@id 表示选取所有名为id的属性 |
// Employee [@*] 表示选取所有具有任何属性的Employee元素 |
XPath注入攻击是指利用XPath 解析器的松散输入与容错特性,在URL、表单或其他信息上附带恶意的XPath查询代码,以获得权限信息的访问权并更改这些信息。由于XML结构的数据没法进行详细的权限控制,所以一旦有XPath注入攻击会导致整个XML文件的数据都会被泄露。以下面的存储员工的XML格式为例:
<?xml version="1.0" encoding="utf-8"?>
<Employees>
<Employee ID="1">
<FirstName>Ade</FirstName>
<LastName>Li</LastName>
<UserName>Adel</UserName>
<Password>Test@123</Password>
<Type>Admin</Type>
</Employee>
<Employee ID="2">
<FirstName>Taylor</FirstName>
<LastName>Kuang</LastName>
<UserName>TaylorK</UserName>
<Password>TaylorK@2021</Password>
<Type>User</Type>
</Employee>
</Employees>
最经典的就是一个员工登录,通过XPath查询看是否有此员工,以及密码是否正确。假设用户输入的内容是:用户Ade登录,用户名是Adel,密码是Test@123,XPath查询语句就是://Employee[UserName/text()='Adel' And Password/text()='Test@123'],正好可以查到用户名和密码都匹配,返回登录成功信息。如果用户输入的是:Adel' or 1=1 or 'a'='a , 结果查询的语句就变成://Employee[UserName/text()='Adel' or 1=1 or 'a'='a And Password/text()='Test@123'],结果就是永远为true。这样攻击者就可以在没有用户密码的情况下,登录成功。如果查询页面没有做好保护,攻击者就可以篡改查询数据,获取整个XML存储结构的所有数据,导致信息泄露。 是不是和SQL注入看起来有点像??
在组装查询语句时,可以看到有些特殊字符会破坏原有的查询语句结构,导致XPath注入的发生。因此需要对特殊字符:单引号(') 和双引号(") 进行编码处理,编码处理的方式和HTML一样,如下表:
攻击类型 | 危险字符 | 编码方法 | 例子 |
XPATH | ' | HTML编码 | ' -> ' |
" | HTML编码 | " -> " |
有的地方(例如:ESAPI的老版本的代码里)还说 ^&"*';<>() 都应该进行HTML编码处理。在这里没有看出其必要性,不过,多编码几个字符,会更安全。
如果有不妥之处,希望可以留言指出。谢谢!
参考:
http://www.w3.org/TR/xpath/