在xml文档中禁止使用DTDexception

在C#应用程序中尝试parsingXML文档时遇到此错误:

“出于安全考虑,在这个XML文档中禁止使用DTD,要启用DTD处理,请将XmlReaderSettings上的ProhibitDtd属性设置为false,并将设置传递给XmlReader.Create方法。

作为参考,以下代码的第二行发生exception:

using (XmlReader reader = XmlReader.Create(uri)) { reader.MoveToContent(); //here while (reader.Read()) //(code to parse xml doc follows). 

我对Xml的知识是相当有限的,我不知道DTD处理是什么,也不知道如何做错误消息build议。 有什么可能导致这个问题,以及如何解决它的帮助? 谢谢…

请注意,settings.ProhibitDtd现在已经过时,请使用DtdProcessing:(忽略,分析或禁止的新选项)

 XmlReaderSettings settings = new XmlReaderSettings(); settings.DtdProcessing = DtdProcessing.Parse; 

正如在这篇文章中所说的那样: 亿笑XML DoS攻击是如何工作的?

您应该添加一个限制字符数以避免DoS攻击:

 XmlReaderSettings settings = new XmlReaderSettings(); settings.DtdProcessing = DtdProcessing.Parse; settings.MaxCharactersFromEntities = 1024; 

首先是一些背景。

什么是DTD?

您要parsing的文档包含文档types声明; 如果您查看文档,您可以在附近find以<!DOCTYPE开头并以相应的>结尾的字符序列。 这种声明允许XML处理器根据一组声明来validation文档,这些声明指定了一组元素和属性,并约束了它们可以具有的值或内容。

由于实体也是在DTD中声明的,所以DTD允许处理器知道如何扩展对实体的引用。 (实体pubdate可能被定义为包含文档的发布date,如“2012年12月15日”,并在文档中多次提及为&pubdate; – 由于实际date只在实体声明中给出一次,这个用法使得更容易保持文档中出版date的各种引用一致)。

DTD是什么意思?

文档types声明具有纯粹的声明性含义:在XML规范中定义的语法中可以在这样和那样的位置find此文档types的模式。

一些对XML基础知识掌握较弱的人编写的软件对于声明的含义有一个基本的混淆, 它假设文档types声明的含义不是声明性的 (模式在那里),而是必须的 (请validation这个文档)。 你正在使用的parsing器似乎是这样一个parsing器; 它假定通过处理一个具有文档types声明的XML文档,您已经请求了某种types的处理。 它的作者可能从如何接受用户的运行时参数的补救课程中受益。 (你会发现有些人理解声明性语义是多么的困难:即使是一些XMLparsing器的创build者有时也不能理解它们,而是陷入了命令式的思考。

他们在谈论什么是“安全原因”?

一些有安全意识的人已经决定,DTD处理(validation或实体扩展而没有validation)构成安全风险。 使用实体扩展,很容易制作一个非常小的XML数据stream,当所有实体完全展开时,这些数据stream将扩展成一个非常大的文档。 search有关所谓的“亿笑发作”的信息,如果你想阅读更多。

一个明显的方法来防止百万笑的攻击是那些调用用户提供或不可信数据的parsing器调用parsing器在一个限制内存的数量或分析过程被允许使用的时间的环境中。 自从20世纪60年代中期以来,这种资源限制就成为操作系统的标准组成部分。 然而,对于我来说依然模糊的原因,一些有安全意识的人相信,正确的答案是在没有资源限制的情况下对不受信任的input运行parsing器,显然认为只要您无法validationinput违反商定的模式。

这就是为什么你的系统告诉你,你的数据有安全问题。

对于一些人来说,DTD是一种安全风险的想法听起来更像是偏执狂,而不是好意,但我不相信它们是正确的。 请记住:(a)安全专家需要一个健康的偏执狂;(b)任何真正感兴趣的人都会坚持资源限制 – 在parsing过程中存在资源限制的情况下,DTD是无害。 禁止DTD不是偏执狂,而是拜物教。


现在,在这种背景下…

你如何解决这个问题?

最好的解决办法是向你的供应商投诉,他们被一个老的关于XML安全的故事所吸引,告诉他们如果他们关心安全性,他们应该做一个合理的安全分析,而不是禁止DTD。

同时,如消息所示,您可以“将XmlReaderSettings上的ProhibitDtd属性设置为false,并将设置传递给XmlReader.Create方法”。 如果input实际上是不可信的,那么也可以考虑给过程适当的资源限制。

作为后备(我不build议这样做),您可以在input中注释掉文档types声明。

至于固定这一点,有一点四处张望,我发现这是很简单的添加:

 XmlReaderSettings settings = new XmlReaderSettings(); settings.ProhibitDtd = false; 

并将这些设置传递给create方法。

[更新3/9/2017]

正如一些人指出的,现在禁止使用DTDT。 Aaron Dishno博士在下面的答案显示了替代解决scheme