不使用lxml的resolve_entities选项实现XML实体解析
不开启resolve_entities完成XML实体解析的方案
RSPEC-2755是Sonar针对XML外部实体注入(XXE)风险的检测规则,直接开启resolve_entities=True会允许解析任意外部实体,确实存在安全隐患。你可以通过以下两种方案在不开启该配置的前提下完成实体解析:
方案1:自定义可信实体解析器
lxml支持自定义实体解析回调,你可以仅放行预设的可信实体,完全不需要开启全局的实体解析开关。
实现步骤:
- 保持
XMLParser的resolve_entities为默认值False - 继承
lxml.etree.EntityResolver类,实现resolve方法,仅返回你允许解析的实体内容 - 将自定义解析器实例添加到parser的resolvers列表中
代码示例:
from lxml import etree # 自定义仅处理可信实体的解析器 class CustomEntityResolver(etree.EntityResolver): def resolve(self, system_id, public_id, context): # 示例:仅处理白名单内的实体定义 if system_id == "trusted_entity.dtd": # 返回预设的合法实体定义内容 return self.resolve_string('<!ENTITY custom_entity "预设的实体内容">', context) # 非白名单实体直接跳过解析 return None # 初始化parser,默认不开启resolve_entities parser = etree.XMLParser() # 注册自定义解析器 parser.resolvers.add(CustomEntityResolver()) # 解析XML文件 xml_tree = etree.parse("your_target.xml", parser=parser)
方案2:预替换内部实体
如果你的XML仅包含内部实体,没有外部实体引用,可以先做实体替换再解析:
- 读取XML原始文本,通过正则提取所有
<!ENTITY 实体名 "实体值">格式的内部实体定义,存储为键值对映射表 - 遍历XML文本,把所有
&实体名;格式的引用替换为映射表对应的实体值 - 用默认parser直接解析替换后的XML文本
注意:该方案仅适用于仅含内部实体的场景,不要用于处理未知来源的外部实体引用,避免引入注入风险。
安全提示
无论使用哪种方案,都要严格限制可解析的实体范围,不要开放任意实体的解析权限,避免触发XXE安全漏洞。如果需要处理外部实体,必须对资源来源做白名单校验,仅加载可信域名下的资源。
内容的提问来源于stack exchange,提问作者Ankit Varshney
相关产品推荐
相关产品推荐

