DTD禁止在xml文档中例外

Con*_*orU 41 c# xmlreader xml-parsing

我在尝试解析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).
Run Code Online (Sandbox Code Playgroud)

我对Xml的了解非常有限,我不知道DTD处理是什么,也不知道如何做错误消息的建议.有关可能导致此问题以及如何解决问题的任何帮助?谢谢...

C. *_*een 67

首先,一些背景.

什么是DTD?

您尝试解析的文档包含文档类型声明; 如果你看一下这个文件,你会发现一个字符序列的开头<!DOCTYPE和对应的结尾>.这样的声明允许XML处理器根据一组声明来验证文档,这些声明指定一组元素和属性并约束它们可以具有的值或内容.

由于实体也在DTD中声明,因此DTD允许处理器知道如何扩展对实体的引用.(该实体pubdate可能被定义为包含文件的发布日期,如"2012年12月15日",并在文件中多次提及&pubdate;- 因为实际日期仅给出一次,在实体声明中,此用法使更容易使文档中对发布日期的各种引用保持一致.)

DTD是什么意思?

文档类型声明具有纯粹的声明性含义:在XML规范中定义的语法中,可以在这样的位置找到此文档类型的模式.

一些对XML基础知识缺乏掌握的人编写的软件对于声明的含义存在基本的混淆; 它假设文档类型声明的含义不是声明性的(模式在那里)但是必要(请验证此文档).您正在使用的解析器似乎是这样的解析器; 它假设通过处理具有文档类型声明的XML文档,您已请求某种处理.其作者可能会从如何接受用户的运行时参数的补救课程中受益.(你知道有些人理解声明性语义是多么困难:即使是某些XML解析器的创建者有时也无法理解它们,而是陷入命令性思维中.叹息.)

他们谈论的这些"安全理由"是什么?

一些有安全意识的人已经决定DTD处理(验证或没有验证的实体扩展)构成安全风险.使用实体扩展,可以很容易地创建一个非常小的XML数据流,当所有实体完全扩展时,它会扩展为非常大的文档.如果您想要阅读更多信息,请搜索有关所谓"十亿笑的攻击"的信息.

防止数十亿次笑声攻击的一种显而易见的方法是,对于在用户提供或不受信任的数据上调用解析器的人来说,在限制允许解析过程的内存量或时间的环境中调用解析器.自20世纪60年代中期以来,这种资源限制一直是操作系统的标准部分.然而,由于一些对我来说仍然模糊不清的原因,一些有安全意识的人认为正确的答案是在没有资源限制的情况下在不受信任的输入上运行解析器,显然认为这是安全的,只要你无法验证输入反对商定的架构.

这就是您的系统告诉您数据存在安全问题的原因.

对于某些人来说,DTD是安全风险的想法听起来更像是偏执狂而不是良好意识,但我不相信它们是正确的.记住(a)健康的偏执是安全专家在生活中需要的,以及(b)任何真正对安全感兴趣的人都会在任何情况下都坚持资源限制 - 在解析过程中存在资源限制的情况下,DTD是无害.禁止DTD不是偏执狂,而是拜物教.


现在,有了背景......

你是如何解决这个问题的?

最好的解决方案是向您的供应商抱怨他们已经被一个关于XML安全性的旧妻子的故事所吸引,并告诉他们如果他们关心安全性,他们应该进行合理的安全性分析,而不是禁止DTD.

同时,正如消息所示,您可以"将XmlReaderSettings上的ProhibitDtd属性设置为false并将设置传递给XmlReader.Create方法".如果输入实际上是不可信的,您可能还会研究为进程提供适当的资源限制的方法.

作为后备(我不建议这样做),您可以在输入中注释掉文档类型声明.

  • 那么 tl;dr 就按照错误消息所说的去做吗?我怀疑 OP 与 MS 打开 Connect 条目是否会很快解决他们或您的 DTD 处理问题。 (2认同)
  • 虽然资源耗尽攻击是一个问题,但现在出现了一个更为重要的问题,即外部实体处理攻击[此处记录](https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing).实际上,它可能允许攻击者从您的服务器或网络中读取文件.默认设置仍然可能是正确的! (2认同)
  • `System.Xml.XmlReaderSettings.ProhibitDtd是过时:使用XmlReaderSettings.DtdProcessing财产instead.`见AaronD的答案. (2认同)

Dr.*_*hno 32

请注意,settings.ProhibitDtd现在已过时,请改用DtdProcessing :( Ignore,Parse或Prohibit的新选项)

XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Parse;
Run Code Online (Sandbox Code Playgroud)

并且正如这篇文章所述: 亿万笑如何嘲笑XML DoS攻击?

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

XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Parse;
settings.MaxCharactersFromEntities = 1024;
Run Code Online (Sandbox Code Playgroud)


Con*_*orU 29

至于解决这个问题,通过一些环顾四周我发现它就像添加一样简单:

XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
Run Code Online (Sandbox Code Playgroud)

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

[更新3/9/2017]

正如一些人所指出的,.ProhibitDTDT现已弃用.下面的Aaron Dishno博士的答案显示了替代解决方案

  • 从最新的(4.5.1).Net框架开始,`.ProhibitDtd`现在已经过时了,应该使用`settings.DtdProcessing = DtdProcessing.Ignore`来获得上述等价物. (28认同)