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

时间:2013-01-09 08:25:17

标签: c# asp.net .net xml xml-parsing

我们对代码进行了安全审核,他们提到我们的代码容易受到外部实体(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)。 任何人都可以帮我错过的地方吗? 任何帮助表示赞赏!

3 个答案:

答案 0 :(得分:36)

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

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

如果要过滤这些网址的来源(例如,仅允许某些域),只需从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。只需将nullResolveUri()返回保存您的代码即可。如果允许URI,您只需返回默认的XmlUrlResolver.ResolveUri()实现。

使用它:

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

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

答案 1 :(得分:3)

所以最好使用

new XmlDocument { XmlResolver = null };

有趣的是,从.net 4.5.2和4.6开始,默认解析器的行为有所不同,并且没有隐含地使用XmlUrlResolver来解析我看到的任何网址或位置。

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

答案 2 :(得分:0)

将 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)