53

尝试在 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 处理是什么,也不知道如何执行错误消息提示的操作。关于可能导致此问题的原因以及如何解决此问题的任何帮助?谢谢...

4

4 回答 4

78

首先,一些背景。

什么是 DTD?

您尝试解析的文档包含文档类型声明;如果您查看文档,您会发现在开头附近有一串以相应的 . 开头<!DOCTYPE和结尾的字符>。这样的声明允许 XML 处理器根据一组声明验证文档,这些声明指定一组元素和属性并限制它们可以具有的值或内容。

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

DTD 是什么意思?

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

一些由对 XML 基础知识不甚了解的人编写的软件对声明的含义存在基本的混淆;它假定文档类型声明的含义不是声明性的(架构在那边),而是命令性的(请验证此文档)。您正在使用的解析器似乎就是这样的解析器;它假定通过将具有文档类型声明的 XML 文档交给它,您已经请求了某种处理。它的作者可能会从有关如何接受用户的运行时参数的补习课程中受益。(您会看到某些人理解声明性语义是多么困难:即使是某些 XML 解析器的创建者有时也无法理解它们,而是陷入了命令式思维。叹息。)

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

一些有安全意识的人认为 DTD 处理(验证,或未经验证的实体扩展)构成安全风险。使用实体扩展,可以很容易地制作一个非常小的 XML 数据流,当所有实体都完全展开时,它会扩展为一个非常大的文档。如果您想了解更多信息,请搜索有关所谓的“十亿笑声攻击”的信息。

防止十亿笑攻击的一种明显方法是,对于那些在用户提供或不受信任的数据上调用解析器的人来说,在限制内存量或允许解析过程消耗的时间的环境中调用解析器。自 1960 年代中期以来,此类资源限制一直是操作系统的标准部分。然而,出于对我来说仍然模糊不清的原因,一些具有安全意识的人认为正确的答案是在不受资源限制的情况下对不受信任的输入运行解析器,他们显然认为只要您无法验证输入是安全的反对商定的模式。

这就是为什么您的系统会告诉您您的数据存在安全问题。

对于某些人来说,DTD 是一种安全风险的想法听起来更像是偏执狂,而不是理智,但我不相信他们是正确的。请记住 (a) 健康的偏执狂是安全专家在生活中所需要的,并且 (b) 任何真正对安全感兴趣的人在任何情况下都会坚持资源限制——在解析过程中存在资源限制的情况下,DTD 是无害。禁止 DTD 不是偏执狂,而是拜物教。


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

你如何解决这个问题?

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

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

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

于 2012-12-13T19:59:14.860 回答
43

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

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

正如这篇文章所述: 十亿笑 XML DoS 攻击是如何工作的?

您应该限制字符数以避免 DoS 攻击:

XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Parse;
settings.MaxCharactersFromEntities = 1024;
于 2015-02-11T16:29:01.123 回答
29

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

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

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

[2017 年 3 月 9 日更新]

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

于 2012-12-19T16:50:03.760 回答
-2

在尝试所有上述答案均未成功后,我将服务用户从 service@mydomain.com 更改为service@mydomain.onmicrosoft.com,现在该应用程序在 azure 中运行时可以正常工作。

或者,如果您在可以更好地控制的环境中遇到此问题;您可以将以下内容粘贴到您的主机文件中:

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
于 2020-02-12T13:08:41.677 回答