如何防止 XXE 攻击(.NET 中的 XmlDocument)

Posted

技术标签:

【中文标题】如何防止 XXE 攻击(.NET 中的 XmlDocument)【英文标题】:How to prevent XXE attack (XmlDocument in .NET) 【发布时间】:2012-12-23 06:00:47 【问题描述】:

我们对我们的代码进行了安全审计,他们提到我们的代码容易受到外部实体 (XXE) 攻击。我正在使用以下代码 -

string OurOutputXMLString=
"<ce><input><transaction><length>00000</length><tran_type>Login</tran_type></transaction><user><user_id>ce_userid</user_id><subscriber_name>ce_subscribername</subscriber_name><subscriber_id>ce_subscriberid</subscriber_id><group_id>ce_groupid</group_id><permissions></permissions></user><consumer><login_details><username>UnitTester9</username><password>pDhE5AsKBHw85Sqgg6qdKQ==</password><pin>tOlkiae9epM=</pin></login_details></consumer></input></ce>"

 XmlDocument xmlDoc = new XmlDocument();
 xmlDoc.LoadXml(OurOutputXMLString);

在审计报告中,他们说它失败了,因为 XML 实体可以包含可以在预期控制之外解析的 URL。 XML 实体解析器将尝试解析和检索外部引用。如果攻击者控制的 XML 可以提交给这些函数之一,那么攻击者就可以访问有关内部网络、本地文件系统或其他敏感数据的信息。 为了避免这种情况,我编写了以下代码,但它不起作用。

MemoryStream stream =
    new MemoryStream(System.Text.Encoding.Default.GetBytes(OurOutputXMLString));

XmlReaderSettings settings = new XmlReaderSettings();

settings.DtdProcessing = DtdProcessing.Prohibit;
settings.MaxCharactersFromEntities = 6000;
XmlReader reader = XmlReader.Create(stream, settings);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(reader);

但我可以在这里看到阅读器没有任何价值可以加载到xmlDoc(XmlDocument)。 任何人都可以在我遗漏的地方提供帮助吗?

【问题讨论】:

如果您确定不使用外部资源,您可以控制 XmlDocument 的 XMLResolver 使用的凭据。有关示例,请参阅msdn.microsoft.com/en-us/library/…。在这种情况下,您可以将 XmlResolver 的凭据设置为只有有限访问权限的帐户,因此任何检索资源的尝试都可以通过 NT 权限进行控制。 事实上,这里有一篇非常有用的 MSDN 文章解决了您的问题:msdn.microsoft.com/en-us/magazine/ee335713.aspx 【参考方案1】:

使用XmlDocument.XmlResolver 属性提供的XmlResolver 解析外部资源。如果您的 XML 文档**不应包含任何外部资源**(例如 DTD 或模式),只需将此属性设置为 null

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.XmlResolver = null;
xmlDoc.LoadXml(OurOutputXMLString);

如果您想过滤这些 URL 的来源(例如只允许某些域),只需从 XmlUrlResolver 派生您自己的类并覆盖 ResolveUri() 方法。在那里您可以检查 URL 是什么并对其进行清理(例如,您可以只允许本地网络中的 URL 或来自受信任来源的 URL)。

例如:

class CustomUrlResovler : XmlUrlResolver

    public override Uri ResolveUri(Uri baseUri, string relativeUri)
    
        Uri uri = new Uri(baseUri, relativeUri);
        if (IsUnsafeHost(uri.Host))
            return null;

        return base.ResolveUri(baseUri, relativeUri);
    

    private bool IsUnsafeHost(string host)
    
        return false; 
    

IsUnsafeHost() 是一个自定义函数,用于检查给定主机是否被允许。有关一些想法,请参阅此处的this post。只需从ResolveUri() 返回null保存您的代码免受此类攻击。如果允许 URI,您可以简单地返回默认的 XmlUrlResolver.ResolveUri() 实现。

使用它:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.XmlResolver = new CustomUrlResolver();
xmlDoc.LoadXml(OurOutputXMLString);

有关如何解析 XML 外部资源的更多详细信息,请阅读 MS Docs 上的Resolving External Resources。如果您的代码比此示例更复杂,那么您绝对应该阅读 Remarks section 以获得 XmlDocument.XmlResolver 属性。

【讨论】:

哇!感谢阿德里亚诺,这对我有用。感谢 Dash 提供的信息。【参考方案2】:

所以更好用

new XmlDocument  XmlResolver = null ;

有趣的是,从 .net 4.5.2 和 4.6 开始,默认解析器的行为有所不同,并且不会预先隐式使用 XmlUrlResolver 来解析我所看到的任何 url 或位置。

//In pre 4.5.2 it is a security issue.
//In 4.5.2 it will not resolve any more the url references in dtd and such, 
//Still better to avoid the below since it will trigger security warnings.
new XmlDocument(); 

【讨论】:

【参考方案3】:

将 XmlReaderSettings.DtdProcessing 设置为 DtdProcessing.Prohibit 在 .NET 4.7.2 中完全可以正常工作。这是我曾经测试过的。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE demo 
[
  <!ELEMENT demo ANY >
  <!ENTITY % extentity SYSTEM "https://www.hl7.org/documentcenter/public/wg/structure/CDA.xsl">
  %extentity;
]>
<test>
    Some random content
</test>

将上述内容保存在一个文件中,并从以下c#代码片段中读取该文件。

XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
settings.MaxCharactersFromEntities = 6000;
//The following stream should be the filestream of the above content.
XmlReader reader = XmlReader.Create(stream, settings);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(reader);

我得到以下异常。

For security reasons DTD is prohibited in this XML document. To enable DTD 
processing set the DtdProcessing property on XmlReaderSettings to Parse and 
pass the settings into XmlReader.Create method.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.ParseDoctypeDecl()
at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
at System.Xml.XmlLoader.LoadNode(Boolean skipOverWhitespace)
at System.Xml.XmlLoader.LoadDocSequence(XmlDocument parentDoc)
at System.Xml.XmlDocument.Load(XmlReader reader)

【讨论】:

以上是关于如何防止 XXE 攻击(.NET 中的 XmlDocument)的主要内容,如果未能解决你的问题,请参考以下文章

XML (XXE) 注入Payload List

利用XML外部实体注入XXE攻击漏洞

如何防止 ASP.NET MVC 应用程序中的 DoS 攻击?

Excel中的XXE攻击

XML注入详解 xxe注入攻击

防止 asp.net Web 表单中的跨站点请求伪造 (csrf) 攻击