xml 文档异常中禁止的 DTD

Posted

技术标签:

【中文标题】xml 文档异常中禁止的 DTD【英文标题】:DTD prohibited in xml document exception 【发布时间】:2012-12-01 00:02:35 【问题描述】:

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

【问题讨论】:

您是否采取了错误信息中列出的步骤?如果没有,为什么它们不适合你? 【参考方案1】:

首先,一些背景。

什么是 DTD?

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

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

DTD 是什么意思?

文档类型声明具有纯粹的声明性意义:可以在这样那样的位置找到该文档类型的模式,按照 XML 规范中定义的语法,可以在这样那样的位置找到。

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

他们所说的这些“安全原因”是什么?

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

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

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

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


现在,背景不碍事...

你如何解决这个问题?

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

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

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

【讨论】:

所以 tl;dr 只是按照错误消息所说的做?我怀疑使用 MS 打开 Connect 条目的 OP 会很快解决他们或您的 DTD 处理问题。 感谢您提供的信息,帮助我了解问题发生的原因。至于怎么解决,就是多加两行代码就行了。 虽然资源耗尽攻击是一个问题,但现在在外部实体处理攻击documented here 中出现了一个更重要的问题。实际上,它可能允许攻击者从您的服务器或网络读取文件。默认设置可能仍然是正确的! 谢谢。这是另一个有趣的安全分析案例,对我来说毫无意义。有问题的外部实体在本地系统上。解析器在本地系统上运行。浏览器中使用的同源策略足以阻止对它们的访问,并且在任何情况下,您指出的文章中都没有解释攻击者如何获得对信息的访问权限。该假设似乎假设服务器的解析器将解析后的数据传递回 XML 文档的源,而不是传递给服务器上运行的某些应用程序;不一定如此。 System.Xml.XmlReaderSettings.ProhibitDtd is obsolete: Use XmlReaderSettings.DtdProcessing property instead. 见 AaronD 的回答。【参考方案2】:

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

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

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

[2017 年 3 月 9 日更新]

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

【讨论】:

在最新的 (4.5.1) .Net 框架中,.ProhibitDtd 现已过时,应该使用settings.DtdProcessing = DtdProcessing.Ignore 来实现上述等价物。 请您更新您的答案。 ProhibitDtd 现在已被弃用。 @Dimi,Aaron Dishno 博士的回答,在我下面,解释了这一点,并提供了当前最好的方法以及一些很好的建议。我不希望通过将他的回答作为我自己的回答来获得他的信任或代表。【参考方案3】:

请注意,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;

【讨论】:

【参考方案4】:

在尝试上述所有答案均未成功后,我将服务用户从 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

【讨论】:

以上是关于xml 文档异常中禁止的 DTD的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server Reporting Services显示XML文档错误中禁止的DTD

XML文档类型定义---DTD文档

DTD(文档类型定义)概述

XML--- XML文档类型定义(DTD)

XML 约束

XML之 ------ DTD(文档类型定义)