实际上,它接收内部和外部实体切换的参数。方法签名:
virtual void doctypeDecl (const xercesc::DTDElementDecl& root,
const XMLCh* const public_id,
const XMLCh* const system_id,
const bool has_internal,
const bool has_external)
对于具有外部实体的文件,它得到
has_internal = true and has_external = false
,
以及具有内部实体的文档
has_internal = false and has_external = true
.
在我们的项目中,我们使用的是 libxsd-3.3.0,它使用 xercesc-3.4.1.
为了修补 libxsd 中的 XXE 漏洞,我们应用了以下解决方案https://www.codesynthesis.com/pipermail/xsd-users/2015-September/004689.html。简而言之,解决方案建议将 xercesc::DOMLSParserImpl 子类化并重新实现 doctypeDecl 方法。如果文档具有外部(或内部)实体,我们应该在其中通过 bool 参数得到通知,并且能够根据需要做出反应,例如:
void SecureDOMParser::doctypeDecl (const DTDElementDecl& e,
const XMLCh* const pub_id,
const XMLCh* const sys_id,
const bool hasi,
const bool hase)
{
if (hasi || hase)
ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Gen_NoDTDValidator, fMemoryManager);
DOMLSParserImpl::doctypeDecl (e, pub_id, sys_id, hasi, hase);
}
上面链接提供的解决方案,包含内部和外部实体的示例,我们在测试 XML 中重复使用了这些示例。
原始示例按预期工作,但是,由于我们只需要避免外部实体,解决方案按以下方式调整:
void SecureDOMParser::doctypeDecl (const DTDElementDecl& e,
const XMLCh* const pub_id,
const XMLCh* const sys_id,
const bool hasi,
const bool hase)
{
if (hase) // modified here
ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Gen_NoDTDValidator, fMemoryManager);
DOMLSParserImpl::doctypeDecl (e, pub_id, sys_id, hasi, hase);
}
在这种形式下,它不会抛出具有外部实体的文档。如果用
if (hasi)
代替它确实会抛出。
在 if 子句中添加额外的登录后得到确认,例如:
void SecureDOMParser::doctypeDecl (const DTDElementDecl& e,
const XMLCh* const pub_id,
const XMLCh* const sys_id,
const bool hasi,
const bool hase)
{
if (hasi || hase)
{
// added logging
std::cout << "has external: " << hase << " has internal: " << hasi;
ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Gen_NoDTDValidator, fMemoryManager);
}
DOMLSParserImpl::doctypeDecl (e, pub_id, sys_id, hasi, hase);
}
此日志记录的输出将如开头所述 - 反之亦然。
还有其他人遇到过这个吗?这是已知的错误吗?