XML解析前必须对用户输入做实体编码转义,否则等于为SQL注入开通XML通道;关键是在XML文档构建前、字符串拼接入节点值之前完成转义,而非依赖解析器或解析后处理。

XML解析前必须对用户输入做实体编码转义
不转义就直接塞进XML文档的用户输入,等于给SQL注入开了XML通道。后端若用DocumentBuilder或DOMParser加载未净化的XML,攻击者只需在<id>1</id>里填<id>1' UNION SELECT username||':'||password FROM users-- </id>,再经XML解析还原成原始单引号,就可能触发拼接型SQL注入。
关键不是“要不要转义”,而是“在哪一层转”。必须在XML文档构建前、字符串拼接入XML节点值之前完成——不能依赖XML解析器自带的转义逻辑,它只保格式合法,不保语义安全。
Java中用StringEscapeUtils.escapeXml11()处理用户输入
Apache Commons Text(非老版Lang3)提供严格符合XML 1.1规范的转义,能覆盖、<code>>、"、'、&五类字符,且不会过度编码导致解析失败。
- 别用
StringEscapeUtils.escapeXml()(已废弃),它不处理',而单引号恰恰是SQL注入高频闭合符 - 别在XML解析后对
Node.getTextContent()结果再转义——此时恶意字符已被还原,为时已晚 - 若用JAXB,确保
@XmlValue字段绑定前已由业务层完成转义,JAXB本身不校验内容安全性
MyBatis里避免$拼接XML参数 + 禁用<bind></bind>动态XPath
MyBatis的XML映射文件若出现${id}或<bind name="xpath" value="'//user[@id=' + id + ']'/>,就等于把XML解析权让渡给运行时字符串拼接——攻击者可传入id=1]' or 1=1 or ['=,最终生成//user[@id='1]' or 1=1 or ['='],破坏XPath结构并诱导SQL逻辑变异。
- 所有用户可控字段一律用
#{id},MyBatis会走PreparedStatement,从源头隔离数据与结构 - 禁用
<bind>构造动态XPath;如需条件路由,改用<if test=" id null></bind>等静态标签 - XML配置中关闭
xml-external-general-entities(JDK8u191+默认禁用),防止XXE间接助推SQL注入链路
WAF规则对XML编码绕过基本无效
常见WAF靠正则匹配UNION SELECT、OR 1=1等关键词,但XML编码(如UNION)或双写(UUNIONION)可轻松绕过。更麻烦的是,Base64编码的XML payload(如<id>MScgVU5JT04gU0VMRUNUICo6PC9pZD4=</id>)在解析前根本不会被WAF解码扫描。
真正有效的防线只有两条:一是输入进入XML前强制实体编码,二是数据库查询全程使用预编译参数。中间任何一层松动,XML就能成为SQL注入的隐身隧道。

















