- 静态分析
- SAST
- 应用安全
- 漏洞扫描
- 代码质量
【免费下载链接】codeql
CodeQL: the libraries and queries that power security researchers around the world, as well as code scanning in GitHub Advanced Security
本篇以 CodeQL C++ 查询包 0.1.2 版变更说明(cpp/ql/src/change-notes/released/0.1.2.md)为核心线索,深入讲解 C++ 语言包中的 XXE 检测查询cpp/external-entity-expansion:其漏洞模型、基于流状态(flow state)的数据流分析实现、0.1.2 中扩展支持的 XML 库与解析接口,以及如何参照仓库内的 QL 源码、样例与测试用例来验证告警行为。读完本文,你将能够读懂该查询的建模思路,并掌握修复 XXE 漏洞的安全配置写法与回归测试方法。
变更背景:从新增到扩展
0.1.2 版的变更说明内容非常聚焦,属于"Minor Analysis Improvements":
The "XML external entity expansion" (
cpp/external-entity-expansion) query has been extended to support a broader selection of XML libraries and interfaces.
而回溯 0.1.1 版(cpp/ql/src/change-notes/released/0.1.1.md)可以看到该查询正是在上一版才被引入:
An new query
cpp/external-entity-expansionhas been added. The query detects XML objects that are vulnerable to external entity expansion (XXE) attacks.
也就是说,0.1.1 完成查询的"从无到有",0.1.2 则完成了"从单点支持到更广泛 XML 库/接口覆盖"的扩展。结合当前仓库快照的源码(XXE.ql、XML.qll、Xerces.qll、Libxml2.qll)可见,扩展后的建模面覆盖了 Xerces-C++ 与 libxml2 两大 C/C++ XML 解析库及其多种解析入口。
查询元数据与告警形态
查询本体位于 cpp/ql/src/Security/CWE/CWE-611/XXE.ql,其头注释定义了完整的元数据:
| 元数据项 | 值 | 说明 |
|---|---|---|
@name | XML external entity expansion | 查询显示名 |
@kind | path-problem | 输出"源 → 汇"的完整数据流路径 |
@id | cpp/external-entity-expansion | 稳定查询 ID,被 suite 与 SARIF 引用 |
@problem.severity | warning | 告警级别 |
@security-severity | 9.1 | 安全严重度(对应 CVSS 风格评分区间) |
@precision | high | 低误报承诺 |
@tags | security, external/cwe/cwe-611 | 对应 CWE-611:对 XML 外部实体的不当限制 |
告警文案为:
This $@ is not configured to prevent an XML external entity (XXE) attack.其中$@指向源节点(即 XML 解析器对象的创建/解析调用),并以 "XML parser" 作为链接标签。由于是path-problem,结果会以路径图形式呈现从解析器创建到解析调用的完整流向,便于开发者定位是哪个对象、在哪一步进入了不安全配置状态。
XXE 漏洞检测目标:查询要回答的问题
XXE.qhelp 对该查询的检测目标做了权威说明:用弱配置的 XML 解析器解析不可信 XML 文件,可能触发 XML 外部实体(XXE)攻击,攻击者利用外部实体引用可达:
- 读取系统上的任意文件(信息泄露);
- 实施拒绝服务(DoS);
- 发起服务端请求伪造(SSRF)。
即使解析结果不会返回给用户,DoS 与带外(out-of-band)数据检索技术仍可能窃取敏感数据,因此该问题即便在"结果不外泄"的场景下依然成立。查询的@description同样强调了两类后果:机密数据泄露与拒绝服务(见 XXE.ql)。
实现原理:用"流状态"跟踪解析器配置
该查询的独到之处在于它跟踪的不是普通的污点数据,而是"XML 解析器对象的配置状态"。这一设计体现在 XML.qll 的抽象层中:
流状态类型TXxeFlowState
newtype TXxeFlowState定义了两种配置状态:
TXercesFlowState(int disabledDefaultEntityResolution, int createEntityReferenceNodes):两个布尔位分别记录AbstractDOMParser/SAXParser上setDisableDefaultEntityResolution与setCreateEntityReferenceNodes的取值;TLibXml2FlowState():libxml2 库的状态(无内部维度,其安全性由解析函数传入的xmlParserOption决定)。
抽象库接口XmlLibrary
abstract class XmlLibrary extends string定义了两种谓词:
configurationSource:识别"可能不安全的配置对象"的创建点,并给出初始流状态;configurationSink:识别"用该配置对象解析 XML"的调用点。
XercesFlowState(Xerces.qll)将TXercesFlowState包装成可读写的状态类,并通过encodeXercesFlowState谓词完成状态与两个布尔位的编解码。
状态转换与数据流配置
XxeConfig(见 XXE.ql)实现了DataFlow::StateConfigSig:
isSource/isSink分别委托给各XmlLibrary的configurationSource/configurationSink;isAdditionalFlowStep让XxeFlowStateTransformer(如setDisableDefaultEntityResolution(...)调用)在数据流传播过程中改写流状态;isBarrier在状态发生转换的调用节点阻断旧状态继续传播,从而精确区分"调用前"与"调用后"的配置。
最终由DataFlow::GlobalWithState<XxeConfig>构建全局带状态数据流(XXE.ql),flowPath(source, sink)产出完整路径。值得留意的是,XML.qll 注释明确要求转换谓词必须是幂等的(transform(transform(x)) = transform(x)),这是该实现方式下状态转换的必要约束。
0.1.2 扩展的 XML 库与接口覆盖
"Broader selection of XML libraries and interfaces" 的具体内容,可以从当前仓库的建模文件中还原:
Xerces-C++ 侧(Xerces.qll)
模型以AbstractDOMParser/SAXParser对象及其配置方法为核心。测试目录(cpp/ql/test/query-tests/Security/CWE/CWE-611)中对应的用例文件印证了覆盖面:
- tests.cpp:
XercesDOMParser及其setDisableDefaultEntityResolution、setCreateEntityReferenceNodes组合; - tests2.cpp:
SAXParser变体; - tests3.cpp:
createXMLReader(SAX2 XMLReader)接口; - tests5.cpp:
createLSParser(DOM Level 3 LSParser)接口。
也就是说,0.1.2 的扩展不只是"多认一个类",而是把 Xerces 家族中 DOM(XercesDOMParser、createLSParser)与 SAX(SAXParser、createXMLReader)两条接口线都纳入了同一套状态建模。
libxml2 侧(Libxml2.qll)
Libxml2ParseCall类按函数名登记了解析入口及其xmlParserOption参数位置:
| 函数 | options 参数位置 |
|---|---|
xmlCtxtUseOptions | 1 |
xmlReadFile | 2 |
xmlCtxtReadFile、xmlParseInNodeContext、xmlReadDoc、xmlReadFd | 3 |
xmlCtxtReadDoc、xmlCtxtReadFd、xmlReadMemory | 4 |
xmlCtxtReadMemory、xmlReadIO | 5 |
xmlCtxtReadIO | 6 |
覆盖了文档读取(file/doc/memory/fd/IO)与上下文解析两大入口族。测试文件 tests4.cpp 展示了判别逻辑:传入XML_PARSE_NOENT、XML_PARSE_DTDLOAD或两者按位或组合时告警(BAD),而传入0或XML_PARSE_OPTION_HARMLESS时不告警(GOOD)。
修复建议:按库关闭外部实体处理
XXE.qhelp 给出的通用建议是:解析不可信数据时应禁用外部实体处理,具体做法取决于所用库。同时提醒:部分库(如较新版本的 libxml)默认即禁用实体展开,除非显式开启,否则无需额外操作——这也解释了为何xmlReadFile(..., 0)与XML_PARSE_OPTION_HARMLESS在测试中被判定为安全。
仓库内置的成对样例给出了最直观的修复对照:
不安全写法(XXEBad.cpp)——解析器以默认状态构造,setDisableDefaultEntityResolution为false,可能展开外部实体引用:
XercesDOMParser *parser = new XercesDOMParser(); parser->parse(data); // BAD (parser is not correctly configured, may expand external entity references)安全写法(XXEGood.cpp)——显式关闭默认实体解析:
XercesDOMParser *parser = new XercesDOMParser(); parser->setDisableDefaultEntityResolution(true); parser->parse(data);测试用例进一步揭示了 Xerces 配置的两个维度必须同时满足:仅设setDisableDefaultEntityResolution(true)而setCreateEntityReferenceNodes为false仍会告警(tests.cpp);两者均为true才判定安全(tests.cpp)。同一测试文件还覆盖了配置在运行中途被反复切换的场景(tests.cpp),验证流状态机对状态改写点的处理。
回归测试与预期结果:验证扩展是否生效
该查询配备了完整的 QL 测试套件,位于 cpp/ql/test/query-tests/Security/CWE/CWE-611,包含多组 C++ 测试输入与对应的 XXE.expected 期望输出。期望文件中的#select段列出所有路径结果,例如:
| tests.cpp:17:2:17:2 | *p | ... | call to XercesDOMParser | ... | This $@ is not configured to prevent an XML external entity (XXE) attack. | ... | XML parser | | tests4.cpp:26:34:26:48 | XML_PARSE_NOENT | ... | XML_PARSE_NOENT | ... | This $@ is not configured to prevent an XML external entity (XXE) attack. | ... | XML parser |从期望输出可以看到告警同时覆盖了 Xerces(XercesDOMParser、SAXParser、createXMLReader、createLSParser)与 libxml2(XML_PARSE_NOENT、XML_PARSE_DTDLOAD及其组合、透传的flags变量),这正是 0.1.2"扩展支持更广泛 XML 库与接口"在测试层面的落点。开发者可参照该目录结构为自己的库扩展补充用例,用codeql test run运行后比对.expected文件即可验证建模行为。
关联文档与演进
- 变更记录入口:cpp/ql/src/change-notes/released/0.1.2.md;
- 新增记录(0.1.1):cpp/ql/src/change-notes/released/0.1.1.md;
- 后续版本在 cpp/ql/src/CHANGELOG.md 中持续记录。
从当前仓库整体结构看,该查询与 CWE-611 条目(cpp/ql/src/Security/CWE/CWE-611)下的XML.qll抽象层、Xerces.qll/Libxml2.qll库模型、XXE.qhelp说明及XXEBad.cpp/XXEGood.cpp样例共同构成一个自洽的检测单元。若要为新的 XML 库(如 pugixml、tinyxml)扩展覆盖,推荐路径是:在XML.qll的XmlLibrary抽象类下新增子类实现configurationSource/configurationSink,定义对应的TXxeFlowState分支与幂等的XxeFlowStateTransformer,并在 cpp/ql/test/query-tests/Security/CWE/CWE-611 下补充测试与期望输出。
- 静态分析
- SAST
- 应用安全
- 漏洞扫描
- 代码质量
【免费下载链接】codeql
CodeQL: the libraries and queries that power security researchers around the world, as well as code scanning in GitHub Advanced Security
相关推荐
CodeQL C++ 安全查询解析:`cpp/external-entity-expansion` 如何检测 XXE 攻击
CodeQL C++ 安全查询解析: cpp/external entity expansion 如何检测 XXE 攻击 导读 cpp/ql/src/chang
静态分析SAST应用安全漏洞扫描代码质量CodeQL C++ 安全查询实战:`cpp/toctou-race-condition` 时间检查与使用竞态检测及其改进
CodeQL C++ 安全查询实战: cpp/toctou race condition 时间检查与使用竞态检测及其改进 本文围绕 CodeQL C++ 查询库
静态分析SAST应用安全漏洞扫描代码质量Carbon ERP功能全解析:从库存管理到生产执行的完整流程
Carbon ERP功能全解析:从库存管理到生产执行的完整流程 Carbon是一款专为制造业打造的开源ERP(企业资源计划)系统,集成了MES(制造执行系统)和
企业应用工业制造后端前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考