本系列文章主旨在于介绍一些漏洞类型产生的基本原理,探索最基础的解决问题的措施。
关于xQuery标准的详细信息可以参考http://www.w3.org/TR/xquery/, 这里只做简单介绍。
XQuery语言是用于查询存储在XML数据库的数据的语言,它可以看做是XPath语言的一个超集。主要用到的XQuery的功能包括:
- 构建XQL查询
- 从XML数据库获取信息给web服务或者应用
- 从XML数据库中年获取XML格式的报告
- 把XML数据转换成XHTML
- 快速遍历XML树
- 根据过滤器过滤得到查询的结果
还是用员工信息的例子,employee.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>
假设组装XQuery的查询的代码如下:
String query="for $Employee in doc(Employee.xml)/Employees/Employee[UserName='" +UserName +"'] return $Employee";
查询“Ade”的XQuery查询如下:doc("Employee.xml")/Employees/Employee[UserName="Ade"],返回的结果如下:
<Employee ID="2">
<FirstName>Taylor</FirstName>
<LastName>Kuang</LastName>
<UserName>TaylorK</UserName>
<Password>TaylorK@2021</Password>
<Type>User</Type>
</Employee>
和SQL注入类似,如果用户对于UserName输入的内容修改为 " or ""=",就会导致查询语句修改为:doc("Employee.xml")/Employees/Employee[UserName="" or ""=""],就会查询获取所有用户的信息。或者简单一点用户直接输入 *,也可以达到一样的效果。
由上例可知,XQuery注入主要是在构建XQuery查询的时候,接收了不可信的数据而且没有做输入验证,并且用于动态构建查询语句造成的。根据XQuery查询结果使用的不同环境造成的影响也不同,主要有:
- 泄露系统内部的数据的信息
- 如果用于鉴权,可能会出现越权
- 也可能会导致XML数据库数据被篡改, 可以设置符合条件的数据被update或者delete
- 执行恶意代码
危害这么严重改如何预防呢?
- 如果在设计上避免使用不可信数据构建XQuery是最好的。
- 使用最小权限原则,以防数据被篡改。
- 输入验证,严格的输入验证对于预防注入问题来说,总是必要的。
- XQuery的一些扩展模块可以用于执行命令,建议尽量避免启用这些扩展模块。
- 使用参数化查询,和SQL的参数化查询PrepareStatement类似,示例代码如下:
-
DocumentBuilderFactory docFac = DocumentBuilderFactory.newInstance(); docFac.setNamespaceAware(true); DocumentBUilder builder = docFac.newDocumentBuilder(); Document doc = builder.parse("Employee.xml"); String queryName = request.getParameter("UserName"); XQuery query = new XQueryFactory().createXQuery(new File("queryEmployee.xq")); Map queryFieldValue = new HashMap(); queryFieldValue.put("UserName", queryName); NodeList nodes = query.execute(doc, null, queryFieldValue).toNodes();
- 有时做输入验证会失效,例如, 人名字(O'Neal)中可能会存在单引号,这是需要转义特殊字符,需要转义的字符和转义方法如下:
字 符 | 转 义 | 说明 |
& | & | 有时会被用于引用预定义的实体 |
' | ' | 字符串开始结束标志 |
" | " | 字符串开始结束标志 |
如果有不妥之处,希望可以留言指出。谢谢!
参考: