我在尝试解析C#应用程序中的XML文档时遇到此错误:
“出于安全原因,此XML文档中禁止使用DTD。要启用DTD处理,请将XmlReaderSettings上的ProhibitDtd属性设置为false,并将设置传递给XmlReader.Create方法。”
作为参考,异常发生在以下代码的第二行:
using (XmlReader reader = XmlReader.Create(uri))
{
reader.MoveToContent(); //here
while (reader.Read()) //(code to parse xml doc follows).
我对Xml的了解非常有限,我不知道DTD处理是什么,也不知道如何处理错误消息。有关可能导致此问题以及如何解决问题的任何帮助?感谢...
答案 0 :(得分:64)
首先,一些背景知识。
您要解析的文档包含文档类型声明;如果您查看该文档,您会在开头附近找到以<!DOCTYPE
开头并以相应的>
结尾的字符序列。这样的声明允许XML处理器根据一组声明来验证文档,这些声明指定一组元素和属性并约束它们可以具有的值或内容。
由于实体也在DTD中声明,因此DTD允许处理器知道如何扩展对实体的引用。 (实体pubdate
可能被定义为包含文档的发布日期,如“2012年12月15日”,并在文档中多次被称为&pubdate;
- 因为实际日期仅给出曾经,在实体声明中,这种用法可以更容易地使文档中对发布日期的各种引用保持一致。)
文档类型声明具有纯粹的声明性含义:可以在这样的位置找到XML规范中定义的语法的此文档类型的模式。
对XML基础知识缺乏掌握的人编写的一些软件对于声明的含义存在基本的混淆;它假定文档类型声明的含义不是声明性(架构在那里),而是命令式(请验证此文档)。您正在使用的解析器似乎是这样的解析器;它假设通过处理具有文档类型声明的XML文档,您已请求某种处理。其作者可能会从如何接受用户的运行时参数的补救课程中受益。 (你知道有些人理解声明性语义是多么困难:即使是某些XML解析器的创建者有时也无法理解它们,而是陷入命令式思维中。叹息。)
一些有安全意识的人已经决定DTD处理(验证或未经验证的实体扩展)构成安全风险。使用实体扩展,可以很容易地创建一个非常小的XML数据流,当所有实体完全扩展时,它会扩展为非常大的文档。如果您想要阅读更多信息,请搜索有关所谓“十亿笑的攻击”的信息。
防止数十亿次笑声攻击的一种显而易见的方法是,对于在用户提供或不受信任的数据上调用解析器的人,在限制允许解析过程的内存量或时间的环境中调用解析器。自20世纪60年代中期以来,这种资源限制一直是操作系统的标准部分。然而,由于一些对我来说模糊不清的原因,一些有安全意识的人认为正确的答案是在不受信任的输入上运行解析器而没有资源限制,显然认为这是安全的,只要你使得无法根据商定的模式验证输入。
这就是您的系统告诉您数据存在安全问题的原因。
对某些人来说,DTD是一种安全风险的想法听起来更像是偏执狂而不是好感,但我不相信它们是正确的。记住(a)健康的偏执是安全专家在生活中需要的,以及(b)任何真正对安全感兴趣的人都会坚持资源限制 - 在解析过程中存在资源限制的情况下,DTD是无害。禁止使用DTD不是偏执狂,而是拜物教。
现在,有了背景......
最好的解决方案是向您的供应商抱怨他们已被一个关于XML安全性的旧故事所吸引,并告诉他们如果他们关心安全性,他们应该进行合理的安全性分析,而不是禁止DTD。
同时,正如消息所示,您可以“将XmlReaderSettings上的ProhibitDtd属性设置为false并将设置传递给XmlReader.Create方法。”如果输入实际上是不可信的,您可能还会研究为进程提供适当的资源限制的方法。
作为后备(我不建议这样做),您可以在输入中注释掉文档类型声明。
答案 1 :(得分:30)
请注意,settings.ProhibitDtd现已过时,请改用DtdProcessing :( Ignore,Parse或Prohibit的新选项)
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Parse;
并且如本帖所述:How does the billion laughs XML DoS attack work?
您应该为字符数添加限制以避免DoS攻击:
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Parse;
settings.MaxCharactersFromEntities = 1024;
答案 2 :(得分:29)
就解决这个问题而言,通过一些环顾四周我发现它就像添加:
一样简单XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
并将这些设置传递给create方法。
[更新3/9/2017]
正如一些人所指出的,.ProhibitDTDT现已弃用。 Dr. Aaron Dishno下面的答案显示了替代解决方案
答案 3 :(得分:-1)
尝试了所有上述答案后,我将服务用户从service@mydomain.com更改为 service@mydomain.onmicrosoft.com ,现在该应用在天蓝色下正常运行。 / p>
或者,如果您在环境中遇到此问题,则可以更好地控制;您可以将以下内容粘贴到主机文件中:
127.0.0.1 msoid.onmicrosoft.com
127.0.0.1 msoid.mydomain.com
127.0.0.1 msoid.mydomain.onmicrosoft.com
127.0.0.1 msoid.*.onmicrosoft.com