この記事では、LINQ to XML に関連するセキュリティの問題について説明し、セキュリティの露出を軽減するためのガイダンスを提供します。
LINQ to XML のセキュリティの概要
LINQ to XML は、セキュリティ要件が厳しいサーバー側アプリケーションよりもプログラミングの利便性を高めるために設計されています。 ほとんどの XML シナリオは、サーバーにアップロードされた信頼されていない XML ドキュメントを処理するのではなく、信頼できる XML ドキュメントの処理で構成されます。 LINQ to XML は、これらのシナリオに合わせて最適化されています。
不明なソースから信頼されていないデータを処理する必要がある場合は、既知の XML サービス拒否 (DoS) 攻撃を除外するように構成された XmlReader クラスのインスタンスを使用することをお勧めします。
サービス拒否攻撃を軽減するように XmlReader を構成した場合は、そのリーダーを使用して LINQ to XML ツリーを設定し、LINQ to XML のプログラマの生産性の向上の恩恵を受けることができます。 多くの軽減手法では、セキュリティの問題を軽減するように構成されたリーダーを作成し、構成されたリーダーを使用して XML ツリーをインスタンス化します。
XML は、ドキュメントのサイズ、深さ、要素名のサイズなどが無制限であるため、本質的にサービス拒否攻撃に対して脆弱です。 XML の処理に使用するコンポーネントに関係なく、過剰なリソースを使用する場合は、アプリケーション ドメインをリサイクルするように常に準備する必要があります。
XML、XSD、XPath、XSLT 攻撃の軽減策
LINQ to XML は、 XmlReader と XmlWriterに基づいて構築されています。 LINQ to XML では、 System.Xml.Schema および System.Xml.XPath 名前空間の拡張メソッドを介して XSD と XPath がサポートされます。 XmlReader、XPathNavigator、および XmlReader クラスを LINQ to XML と組み合わせて使用すると、XSLT を呼び出して XML ツリーを変換できます。
安全性の低い環境で運用している場合、XML に関連するセキュリティの問題と、 System.Xml、 System.Xml.Schema、 System.Xml.XPath、 System.Xml.Xslのクラスの使用に関連するさまざまな問題があります。 これらの問題には、次のものが含まれますが、これらに限定されません。
- XSD、XPath、XSLT は文字列ベースの言語であり、多くの時間またはメモリを消費する操作を指定できます。 信頼されていないソースから XSD、XPath、または XSLT 文字列を取得するアプリケーション プログラマは、文字列が悪意がないことを検証するか、これらの文字列を評価するとシステム リソースの過剰な消費につながる可能性を監視して軽減する必要があります。
- XSD スキーマ (インライン スキーマを含む) は、本質的にサービス拒否攻撃に対して脆弱です。信頼されていないソースからのスキーマを受け入れてはいけません。
- XSD と XSLT には他のファイルへの参照を含めることができます。このような参照により、クロスゾーン攻撃やクロスドメイン攻撃が発生する可能性があります。
- DTD 内の外部エンティティは、クロスゾーン攻撃とクロスドメイン攻撃を行う可能性があります。
- DTD は、サービス拒否攻撃に対して脆弱です。
- 非常に深い XML ドキュメントは、サービス拒否の問題を引き起こす可能性があります。XML ドキュメントの深さを制限できます。
- 信頼されていないアセンブリの NameTable、 XmlNamespaceManager、 XmlResolver オブジェクトなどのサポート コンポーネントを受け入れないでください。
- 大量のドキュメント攻撃を軽減するために、チャンク単位でデータを読み取ります。
- XSLT スタイル シートのスクリプト ブロックは、さまざまな攻撃を公開する可能性があります。
- 動的な XPath 式を作成する前に、慎重に検証してください。
LINQ to XML のセキュリティに関する問題
この記事のセキュリティの問題は、特定の順序では表示されません。 すべての問題は重要であり、必要に応じて対処する必要があります。
特権の昇格攻撃が成功すると、悪意のあるアセンブリがその環境をより詳細に制御できるようになります。 特権攻撃の昇格が成功すると、データの漏えい、サービス拒否などが発生する可能性があります。
アプリケーションでは、そのデータを表示する権限を持たないユーザーにデータを開示しないでください。
サービス拒否攻撃により、XML パーサーまたは LINQ to XML で大量のメモリまたは CPU 時間が消費されます。 サービス拒否攻撃は、特権攻撃の昇格やデータ攻撃の開示よりも深刻度が低いと見なされます。 ただし、サーバーが信頼されていないソースからの XML ドキュメントを処理する必要があるシナリオでは重要です。
信頼されていない呼び出し元にエラー メッセージを公開しない
エラーの説明により、変換されるデータ、ファイル名、実装の詳細などのデータが表示される場合があります。 エラー メッセージは、信頼されていない呼び出し元に公開しないでください。 すべてのエラーをキャッチし、独自のカスタム エラー メッセージを使用してエラーを報告する必要があります。
イベント ハンドラーで CodeAccessPermissions.Assert を呼び出さないでください
アセンブリには、より少ない権限または大きい権限を持つことができます。 より大きなアクセス許可を持つアセンブリは、コンピューターとその環境をより詳細に制御できます。
より大きなアクセス許可を持つアセンブリ内のコードがイベント ハンドラーで CodeAccessPermission.Assert し、アクセス許可が制限されている悪意のあるアセンブリに XML ツリーが渡されると、悪意のあるアセンブリによってイベントが発生する可能性があります。 イベントは、より大きなアクセス許可を持つアセンブリ内のコードを実行するため、悪意のあるアセンブリは昇格された特権で動作することになります。
Microsoft では、イベント ハンドラーで CodeAccessPermission.Assert を呼び出さないことをお勧めします。
信頼されていないソースからの DTD を受け入れない
DTD 内のエンティティは本質的にセキュリティで保護されていません。 DTD を含む悪意のある XML ドキュメントが原因でパーサーがすべてのメモリと CPU 時間を使用し、サービス拒否攻撃を引き起こす可能性があります。 そのため、LINQ to XML では、DTD 処理は既定で無効になっています。 信頼されていないソースからの DTD を受け入れてはいけません。
信頼されていないソースから DTD を受け入れる例の 1 つは、Web ユーザーが DTD と DTD ファイルを参照する XML ファイルをアップロードできるようにする Web アプリケーションです。 ファイルの検証時に、悪意のある DTD がサーバーに対してサービス拒否攻撃を実行する可能性があります。 信頼されていないソースから DTD を受け入れるもう 1 つの例は、匿名 FTP アクセスも許可するネットワーク共有上の DTD を参照することです。
過剰なバッファー割り当てを回避する
アプリケーション開発者は、非常に大きなデータ ソースがリソース不足やサービス拒否攻撃につながる可能性があることに注意する必要があります。
悪意のあるユーザーが非常に大きな XML ドキュメントを送信またはアップロードすると、LINQ to XML が過剰なシステム リソースを消費する可能性があります。 これは、サービス拒否攻撃を構成できます。 これを回避するには、 XmlReaderSettings.MaxCharactersInDocument プロパティを設定し、読み込むことができるドキュメントのサイズに制限されたリーダーを作成します。 次に、リーダーを使用して XML ツリーを作成します。
たとえば、信頼されていないソースからの XML ドキュメントの予想される最大サイズが 50,000 バイト未満になることがわかっている場合は、 XmlReaderSettings.MaxCharactersInDocument 100,000 に設定します。 これにより、XML ドキュメントの処理が妨がされることはありません。同時に、大量のメモリを消費するドキュメントがアップロードされる可能性があるサービス拒否の脅威が軽減されます。
余分なエンティティの拡張を回避する
DTD を使用する場合の既知のサービス拒否攻撃の 1 つは、エンティティの過剰な拡張を引き起こすドキュメントです。 これを回避するには、 XmlReaderSettings.MaxCharactersFromEntities プロパティを設定し、エンティティの拡張の結果として得られる文字数に制限されたリーダーを作成します。 次に、リーダーを使用して XML ツリーを作成します。
XML 階層の深さを制限する
サービス拒否攻撃の可能性の 1 つは、階層が過度に深いドキュメントが送信されたときです。 これを回避するには、要素の深さをカウントする独自のクラスで XmlReader をラップします。 深さが所定の妥当なレベルを超えた場合は、悪意のあるドキュメントの処理を終了できます。
信頼されていない XmlReader または XmlWriter の実装から保護する
管理者は、外部から提供された XmlReader または XmlWriter の実装に厳密な名前があり、マシン構成に登録されていることを確認する必要があります。 これにより、リーダーまたはライターを装った悪意のあるコードが読み込まれなくなります。
XName を参照するオブジェクトを定期的に解放する
特定の種類の攻撃から保護するには、アプリケーション プログラマは、アプリケーション ドメイン内の XName オブジェクトを参照するすべてのオブジェクトを定期的に解放する必要があります。
ランダムな XML 名から保護する
信頼されていないソースからデータを取得するアプリケーションでは、カスタム コードでラップされた XmlReader を使用して、ランダムな XML 名と名前空間の可能性を調べることを検討する必要があります。 このようなランダムな XML 名と名前空間が検出された場合、アプリケーションは悪意のあるドキュメントの処理を終了できます。
特定の名前空間内の名前の数 (名前空間のない名前を含む) を妥当な制限に制限する場合があります。
信頼されていないコンポーネントにデータを渡す前に LINQ to XML オブジェクトを XML テキストにシリアル化する
LINQ to XML を使用して、さまざまなアプリケーション コンポーネントが XML ツリーとしてコンポーネント間で渡される XML データを読み込み、検証、クエリ、変換、更新、および保存する処理パイプラインを構築できます。 これは、XML テキストへのオブジェクトの読み込みとシリアル化のオーバーヘッドがパイプラインの末尾でのみ行われるため、パフォーマンスを最適化するのに役立ちます。 ただし、開発者は、1 つのコンポーネントによって作成されたすべての注釈とイベント ハンドラーに他のコンポーネントからアクセスできる点に注意する必要があります。 これにより、コンポーネントの信頼レベルが異なる場合、さまざまな脆弱性が発生する可能性があります。 信頼されていないコンポーネント間でセキュリティで保護されたパイプラインを構築するには、信頼されていないコンポーネントにデータを渡す前に、LINQ to XML オブジェクトを XML テキストにシリアル化する必要があります。
一部のセキュリティは、共通言語ランタイム (CLR) によって提供されます。 たとえば、プライベート クラスを含まないコンポーネントは、そのクラスによってキー付けされた注釈にアクセスできません。 ただし、注釈は読み取ることができないコンポーネントによって削除できます。 これは改ざん攻撃として使用される可能性があります。
こちらも参照ください
.NET