发票导入接口收到一段带 DOCTYPE 的 xml,返回的解析结果里出现了 /etc/passwd 的内容。实体定义里引用了 file:// 协议,解析器照单执行。碰到这种情况,我一般先确认改动有没有真的生效。
原因不复杂,解析器默认允许 DTD 和外部实体,遇到 SYSTEM 声明就去读本地文件或者发网络请求。读取结果被实体替换进文档,再随业务字段回显出来。有些解析器还会因此卡在外部请求上。
「XXE 外部实体」相关的日志我一般连着看前后五分钟,单看一条报错经常判断不出是哪一步失败。改完顺手把文档补一句,省得下次自己重新推一遍。
from lxml import etree p = etree.XMLParser(resolve_entities=False, no_network=True, load_dtd=False) doc = etree.fromstring(raw, p)
监控和日志的时间要对上,时区不一致会多绕很大一圈。
具体做法是,解析前关掉 DTD 和外部实体 两个开关都要关;换用默认安全的解析库版本 并显式设置特性;对 xml 做结构校验 只接受约定的字段;把解析服务放到不能访问内网的网段。
最后用这个标准收尾,同一段 xml 再导入 返回解析失败 响应里没有 passwd 内容 也没有对外请求。
