web-dev-qa-db-ja.com

DTDはXMLドキュメントの例外で禁止されています

C#アプリケーションでXMLドキュメントを解析しようとすると、このエラーが発生します。

「セキュリティ上の理由から、このXMLドキュメントではDTDは禁止されています。DTD処理を有効にするには、XmlReaderSettingsのProhibitDtdプロパティをfalseに設定し、設定をXmlReader.Createメソッドに渡します。」

参考のため、次のコードの2行目で例外が発生しました。

using (XmlReader reader = XmlReader.Create(uri))
{
    reader.MoveToContent(); //here

    while (reader.Read()) //(code to parse xml doc follows).

私のXmlの知識はかなり限られており、DTD処理が何であるか、エラーメッセージが示唆することをどのように行うかについてはわかりません。これを引き起こしている可能性のあるものとその修正方法に関するヘルプはありますか?ありがとう...

41
ConnorU

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;
31

まず、いくつかの背景。

DTDとは何ですか?

解析しようとしているドキュメントには、ドキュメントタイプ宣言が含まれています。ドキュメントを見ると、<!DOCTYPEで始まり、対応する>で終わる文字列の先頭近くにあります。このような宣言により、XMLプロセッサは、要素と属性のセットを指定し、保持できる値またはコンテンツを制限する宣言セットに対してドキュメントを検証できます。

エンティティもDTDで宣言されているため、DTDを使用すると、プロセッサはエンティティへの参照を展開する方法を知ることができます。 (エンティティpubdateは、「2012年12月15日」のようにドキュメントの公開日を含むように定義され、ドキュメント内で&pubdate;と呼ばれることがあります。実際の日付が与えられているためです。エンティティ宣言で1回だけ使用すると、この使用法により、ドキュメント内の発行日へのさまざまな参照を互いに整合させることが容易になります。

DTDとはどういう意味ですか?

ドキュメントタイプの宣言には、純粋に宣言的な意味があります。XML仕様で定義されている構文のこのドキュメントタイプのスキーマは、そのような場所で見つけることができます。

XMLの基礎を十分に理解していない人々が作成したソフトウェアの中には、宣言の意味に関する基本的な混乱に苦しんでいるものがあります。ドキュメントタイプ宣言の意味はdeclarative(スキーマがそこにある)ではなく、imperative(このドキュメントを検証してください)ではないことを前提としています。使用しているパーサーは、そのようなパーサーのようです。文書型宣言を含むXML文書を渡すことで、特定の種類の処理を要求したと想定しています。その作成者は、ユーザーから実行時パラメーターを受け入れる方法に関する改善コースの恩恵を受ける可能性があります。 (一部の人々が宣言的セマンティクスを理解するのはどれほど難しいかわかります。一部のXMLパーサーの作成者でさえ、それらを理解できず、代わりに命令的思考に陥ることがあります。ため息。)

彼らが話しているこれらの「セキュリティ上の理由」とは何ですか?

一部のセキュリティ志向の人々は、DTD処理(検証、または検証なしのエンティティ拡張)がセキュリティリスクであると判断しています。エンティティ展開を使用すると、すべてのエンティティが完全に展開されたときに非常に大きなドキュメントに展開される非常に小さなXMLデータストリームを簡単に作成できます。さらに読みたい場合は、「billion laughs attack」と呼ばれるものに関する情報を検索してください。

10億笑い攻撃から保護するための1つの明白な方法は、ユーザー提供のデータまたは信頼できないデータに対してパーサーを呼び出し、解析プロセスが消費できるメモリの量または時間を制限する環境でパーサーを呼び出すことです。このようなリソース制限は、1960年代半ばからオペレーティングシステムの標準的な部分でした。しかし、私にはあいまいな理由で、セキュリティを重視する人の中には、正しい答えは信頼できない入力でパーサーを実行することだと考えていますリソース制限なし、これはあなたが安全である限り合意されたスキーマに対して入力を検証できないようにします。

これが、データにセキュリティ上の問題があることをシステムが通知している理由です。

一部の人々にとって、DTDはセキュリティリスクであるという考えは、良識よりも妄想に似ていますが、正しいとは思いません。 (a)健全なパラノイアはセキュリティの専門家が必要とするものであり、(b)セキュリティに本当に関心のある人はいずれにせよリソースの制限を主張することを忘れないでください-解析プロセスにリソースの制限がある場合、DTDは無害。 DTDの禁止は、妄想ではなく、フェティシズムです。


さて、その背景を邪魔にせずに...

どのように問題を修正しますか?

最善の解決策は、XMLセキュリティーに関する古い妻の話にうんざりしているベンダーに苦情を訴え、セキュリティーに関心がある場合は、DTDを禁止するのではなく合理的なセキュリティー分析を行う必要があることを伝えることです。

一方、メッセージが示すように、「XmlReaderSettingsのProhibitDtdプロパティをfalseに設定し、設定をXmlReader.Createメソッドに渡すことができます。」入力が実際に信頼できない場合、プロセスに適切なリソース制限を与える方法を検討することもできます。

また、フォールバック(これはお勧めしません)として、入力のドキュメントタイプ宣言をコメントアウトできます。

これを修正する限り、少し見て回ると、追加するのと同じくらい簡単であることがわかりました:

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

これらの設定をcreateメソッドに渡します。

[2017年3月9日更新]

一部の人が指摘したように、.ProhibitDTDTは非推奨になりました。 Dr。Aaron Dishno の回答、以下は、代替ソリューションを示しています

29
ConnorU