提问者:小点点

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


我们对我们的代码进行了安全审计,他们提到我们的代码容易受到外部实体(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没有任何值可以加载到< code > XML document(XML document)中。谁能帮忙我哪里漏了东西?


共3个答案

匿名用户

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

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

如果您想过滤这些URL的来源(例如只允许某些域),只需从XmlUrlResolver派生您自己的类并覆盖ResolveUri()方法。在那里,您可以检查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; 
    }
}

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

要使用它:

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

有关如何解析XML外部资源的更多详细信息,请参阅解析MS文档上的外部资源。如果您的代码比本例更复杂,那么您绝对应该阅读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.Prohibition 在 .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)