首先,提供一些背景信息。
什么是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方法。”如果输入确实不可信,则还可以探索给进程提供适当资源限制的方法。
作为一种备选方案(我不推荐这样做),您可以在输入中注释掉文档类型声明。