XML注入攻击是什么
XML注入攻击是指攻击者通过在XML数据的输入位置插入恶意构造的XML片段,干扰XML解析器的正常解析逻辑,进而篡改XML文档结构、窃取敏感数据或执行未授权操作的安全攻击方式。这类攻击通常发生在应用接收用户可控的XML输入,且未对输入内容进行严格校验的场景中。
常见攻击类型
XML注入攻击主要分为两类,不同类型的攻击原理和影响范围有所区别:
- XML结构注入:攻击者插入的恶意内容会破坏原有XML的标签闭合规则,新增或修改XML节点,导致解析后的数据不符合预期。比如在用户注册的XML输入中插入额外的用户信息节点,篡改注册逻辑。
- XML外部实体注入(XXE):攻击者利用XML解析器支持外部实体的特性,构造包含外部实体引用的XML内容,读取服务器本地文件、发起内网请求等。例如通过外部实体读取/etc/passwd文件内容。
攻击示例
假设某应用接收用户提交的XML格式的用户信息,解析后存储到数据库,正常的用户输入XML如下:
<user>
<name>张三</name>
<age>20</age>
</user>
如果攻击者输入的内容包含恶意XML片段:
<user>
<name>张三</name>
<age>20</age>
</user>
<user>
<name>攻击者</name>
<age>99</age>
</user>
若应用未做校验直接解析,就会在解析结果中新增一个攻击者构造的用户节点,完成数据篡改。
如何预防XML注入攻击
1. 严格校验输入内容
对所有用户可控的XML输入内容做白名单校验,只允许符合预期格式的字符和标签出现,禁止出现未定义的XML标签、特殊字符。比如用户只需要输入姓名和年龄,就校验输入中只包含<name>、<age>标签,且年龄内容仅为数字。
2. 禁用XML外部实体
XXE攻击的核心是利用XML外部实体,因此在解析XML时,需要显式禁用外部实体加载功能。以下是Java中禁用外部实体的示例代码:
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
public class XmlParserUtil {
public static void parseXml(String xmlContent) throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 禁用外部实体
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
factory.setXIncludeAware(false);
factory.setExpandEntityReferences(false);
DocumentBuilder builder = factory.newDocumentBuilder();
builder.parse(new ByteArrayInputStream(xmlContent.getBytes("UTF-8")));
}
}
3. 使用参数化方式处理XML数据
如果需要动态生成XML内容,不要直接拼接用户输入的字符串,而是使用XML处理库提供的API动态构建XML节点,从根源上避免注入问题。以下是Python中使用xml.etree.ElementTree构建XML的示例:
import xml.etree.ElementTree as ET
def build_user_xml(user_name, user_age):
# 使用API构建XML节点,不直接拼接字符串
root = ET.Element("user")
name_node = ET.SubElement(root, "name")
name_node.text = user_name
age_node = ET.SubElement(root, "age")
age_node.text = str(user_age)
return ET.tostring(root, encoding="utf-8").decode("utf-8")
# 即使用户输入包含恶意内容,也只会被当作普通文本处理
xml_result = build_user_xml("张三</name><age>99</age>", "20")
print(xml_result)
4. 限制XML解析的深度和大小
设置XML解析器的最大解析深度、最大文件大小,避免攻击者提交超大的恶意XML内容引发拒绝服务攻击,同时减少注入内容的影响范围。
5. 避免直接输出XML解析结果到响应
如果需要将XML解析后的内容返回给用户,要对输出内容做转义处理,避免解析后的恶意内容被浏览器当作可执行代码执行,进一步降低攻击影响。
总结
XML注入攻击的核心原因是XML输入未校验、解析配置不当,开发者只要在输入校验、解析配置、XML构建三个环节做好防护,就能有效避免这类攻击。在开发涉及XML处理的业务时,建议优先使用成熟的XML安全处理库,减少手动处理XML带来的安全隐患。