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

本文关键字:中的 XmlDocument net 何防止 XXE 攻击 | 更新日期: 2023-09-27 17:51:08

我们对代码进行了安全审计,他们提到我们的代码容易受到外部实体(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);

但是我可以在这里看到reader没有任何值可以加载到xmlDoc(XmlDocument)。谁能帮我找一下我丢的东西吗?

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

外部资源使用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()是一个自定义函数,用于检查给定的主机是否被允许。看看这篇关于SO的文章。只需从ResolveUri()返回null,保存您的代码免受此类攻击。如果URI是允许的,您可以简单地返回默认的XmlUrlResolver.ResolveUri()实现。

使用它:

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

有关如何解析XML外部资源的更多细节,请参阅MS Docs上的解析外部资源。如果您的代码比这个示例更复杂,那么您绝对应该阅读XmlDocument的备注部分。XmlResolver财产。

所以最好使用

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(); 

设置XmlReaderSettings。DtdProcessing到DtdProcessing。禁止在。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)