この記事では、この API のリファレンス ドキュメントに補足的な解説を提供します。
SignedXml クラスは、World Wide Web Consortium (W3C) XML Signature Syntax and Processing Specification (XMLDSIG (XML Digital Signature) とも呼ばれます) の .NET 実装です。 XMLDSIG は、標準ベースの相互運用可能な方法で、XML ドキュメントまたは URI (Uniform Resource Identifier) からアドレス指定可能なその他のデータのすべてまたは一部に署名して検証します。
標準の方法でアプリケーションまたは組織間で署名付き XML データを共有する必要がある場合は常に、 SignedXml クラスを使用します。 このクラスを使用して署名されたデータは、XMLDSIG の W3C 仕様の準拠した実装によって検証できます。
SignedXml クラスを使用すると、次の 3 種類の XML デジタル署名を作成できます。
署名の種類 | 説明 |
---|---|
エンベロープ署名 | 署名は、署名される XML 要素内に含まれています。 |
署名を包み込む | 署名付き XML は、 <Signature> 要素内に含まれています。 |
内部デタッチされた署名 | 署名と署名付き XML は同じドキュメント内にありますが、どちらの要素にも他の要素は含まれています。 |
また、外部デタッチ署名と呼ばれる 4 番目の種類の署名もあります。これは、データと署名が別々の XML ドキュメントにある場合です。 外部デタッチされたシグネチャは、 SignedXml クラスではサポートされていません。
XML 署名の構造
XMLDSIG は、要素を作成します。この要素には、XML ドキュメントまたは URI からアドレス指定可能なその他のデータのデジタル署名が含まれます。
<Signature>
要素には、必要に応じて、署名を検証するキーを検索する場所と、署名に使用された暗号化アルゴリズムに関する情報を含めることができます。 基本的な構造は次のとおりです。
<Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>Base64EncodedValue==</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>AnotherBase64EncodedValue===</SignatureValue>
</Signature>
この構造の主な部分は次のとおりです。
<CanonicalizationMethod>
要素署名の検証のために、
Signature
要素を XML/テキストからバイトに書き換える規則を指定します。 .NET の既定値は http://www.w3.org/TR/2001/REC-xml-c14n-20010315 であり、信頼できるアルゴリズムを識別します。 この要素は、 SignedInfo.CanonicalizationMethod プロパティによって表されます。<SignatureMethod>
要素<SignatureValue>
で値を生成するために<Signature>
要素に適用された、署名の生成と検証に使用されるアルゴリズムを指定します。 前の例では、 http://www.w3.org/2000/09/xmldsig#rsa-sha1 値は RSA PKCS1 SHA-1 署名を識別します。 SHA-1 の競合の問題により、Microsoft では SHA-256 以上に基づくセキュリティ モデルをお勧めします。 この要素は、 SignatureMethod プロパティによって表されます。<SignatureValue>
要素<Signature>
要素の暗号化署名を指定します。 この署名が検証されない場合、<Signature>
ブロックの一部が改ざんされ、ドキュメントは無効と見なされます。<CanonicalizationMethod>
値が信頼できる限り、この値は改ざんに対して非常に耐性があります。 この要素は、 SignatureValue プロパティによって表されます。<Reference>
要素のURI
属性URI 参照を使用してデータ オブジェクトを指定します。 この属性は、 Reference.Uri プロパティによって表されます。
URI
属性を指定しない、つまり、Reference.Uri プロパティをnull
に設定することは、受信側のアプリケーションがオブジェクトの ID を認識することが期待されることを意味します。 ほとんどの場合、null
URI によって例外がスローされます。 アプリケーションが必要なプロトコルと相互運用している場合を除き、null
URI は使用しないでください。URI
属性を空の文字列に設定すると、ドキュメントのルート要素が署名されていることを示します。これは、エンベロープ署名の形式です。URI
属性の値が #で始まる場合、値は現在のドキュメント内の要素に解決される必要があります。 このフォームは、サポートされている署名の種類 (エンベロープ署名、エンベロープ署名、または内部デタッチ署名) と共に使用できます。それ以外の場合は、外部リソースのデタッチされたシグネチャと見なされ、 SignedXml クラスではサポートされていません。
<Transforms>
要素署名者がダイジェストされたデータ オブジェクトを取得した方法を説明する
<Transform>
要素の順序付きリストが含まれます。 変換アルゴリズムは正規化方法に似ていますが、<Signature>
要素を書き換える代わりに、<Reference>
要素のURI
属性によって識別されるコンテンツを書き換えます。<Transforms>
要素は、TransformChain クラスによって表されます。各変換アルゴリズムは、XML (XPath ノード セット) またはバイトを入力として受け取ると定義されます。 現在のデータの形式が変換入力要件と異なる場合は、変換ルールが適用されます。
各変換アルゴリズムは、XML またはバイトを出力として生成するものとして定義されます。
最後の変換アルゴリズムの出力がバイト単位で定義されていない (または変換が指定されていない) 場合、 正規化メソッド は暗黙的な変換として使用されます (
<CanonicalizationMethod>
要素で別のアルゴリズムが指定された場合でも)。変換アルゴリズムの http://www.w3.org/2000/09/xmldsig#enveloped-signature 値は、ドキュメントから
<Signature>
要素を削除すると解釈されるルールをエンコードします。 それ以外の場合、エンベロープ署名の検証者は署名を含めてドキュメントをダイジェストしますが、署名者は署名が適用される前にドキュメントをダイジェストし、異なる回答が得られました。
<DigestMethod>
要素<Reference>
要素のURI
属性によって識別される変換されたコンテンツに適用するダイジェスト (暗号化ハッシュ) メソッドを識別します。 これは、 Reference.DigestMethod プロパティによって表されます。
正規化方法の選択
別の値を使用する必要がある仕様と相互運用しない限り、値が http://www.w3.org/TR/2001/REC-xml-c14n-20010315される既定の .NET 正規化方法 (XML-C14N 1.0 アルゴリズム) を使用することをお勧めします。 XML-C14N 1.0 アルゴリズムは、XMLDSIG のすべての実装でサポートされている必要があります。これは、適用する暗黙的な最終的な変換であるためです。
コメントの保持をサポートする正規化アルゴリズムのバージョンがあります。 コメントを保持する正規化メソッドは、"表示される記号" の原則に違反するため、推奨されません。 つまり、 <Signature>
要素内のコメントは、シグネチャの実行方法に関する処理ロジックを変更せず、シグネチャ値が何であるかだけを変更します。 弱い署名アルゴリズムと組み合わせると、コメントを含めることにより、攻撃者はハッシュの衝突を強制する自由が不要になり、改ざんされたドキュメントが正当に表示されます。 .NET Framework では、組み込みの正規化のみが既定でサポートされます。 追加またはカスタムの正規化をサポートするには、 SafeCanonicalizationMethods プロパティを参照してください。 ドキュメントで、 SafeCanonicalizationMethods プロパティで表されるコレクションにない正規化メソッドを使用している場合、 CheckSignature メソッドは false
を返します。
注
非常に防御的なアプリケーションでは、署名者が SafeCanonicalizationMethods コレクションから使用するとは思わない値を削除できます。
参照値は改ざんから安全ですか?
はい。 <Reference>
値は改ざんから安全です。 .NET は、<Reference>
値とそれに関連する変換を処理する前に<SignatureValue>
計算を検証し、悪意のある処理命令の可能性を回避するために早期に中止します。
署名する要素を選択する
可能であれば、 URI
属性に "" の値を使用することをお勧めします (または、 Uri プロパティを空の文字列に設定します)。 つまり、ドキュメント全体がダイジェスト計算のために考慮されます。つまり、ドキュメント全体が改ざんから保護されます。
id 属性が "foo" である要素を参照して、#foo などのアンカーの形式で URI
値を確認することは非常に一般的です。 残念ながら、コンテキストではなくターゲット要素のコンテンツのみが含まれるため、これを改ざんするのは簡単です。 この区別を悪用することは、XML シグネチャ ラッピング (XSW) と呼ばれます。
アプリケーションでコメントがセマンティックであると見なされる場合 (XML を扱う場合は一般的ではありません)、"ではなく "#xpointer(/)" を使用し、"#foo" ではなく "#xpointer(id('foo'))" を使用する必要があります。 #xpointer のバージョンはコメントを含めると解釈されますが、shortname 形式ではコメントは除外されます。
部分的に保護されたドキュメントのみを受け入れる必要があり、署名で保護されたのと同じコンテンツを確実に読み取る必要がある場合は、 GetIdElement メソッドを使用します。
KeyInfo 要素に関するセキュリティに関する考慮事項
省略可能な <KeyInfo>
要素 (つまり、署名を検証するキーを含む KeyInfo プロパティ) 内のデータは信頼できません。
特に、 KeyInfo 値がベア RSA、DSA、または ECDSA 公開キーを表している場合、署名が有効であることを報告する CheckSignature メソッドにもかかわらず、ドキュメントが改ざんされた可能性があります。 これは、改ざんを行うエンティティが新しいキーを生成し、改ざんされたドキュメントにその新しいキーで再署名する必要があるために発生する可能性があります。 そのため、公開キーが予期される値であることをアプリケーションが確認しない限り、ドキュメントは改ざんされたかのように扱う必要があります。 そのためには、アプリケーションがドキュメント内に埋め込まれている公開キーを調べて、ドキュメント コンテキストの既知の値の一覧に対して検証する必要があります。 たとえば、ドキュメントが既知のユーザーによって発行されたと認識できる場合は、そのユーザーが使用する既知のキーの一覧に対してキーを確認します。
CheckSignature メソッドを使用する代わりに、CheckSignatureReturningKey メソッドを使用して、ドキュメントの処理後にキーを確認することもできます。 ただし、セキュリティを最適化するには、事前にキーを確認する必要があります。
または、 <KeyInfo>
要素の内容を読み取るのではなく、ユーザーの登録済みの公開キーを試してみることを検討してください。
X509Data 要素に関するセキュリティに関する考慮事項
省略可能な <X509Data>
要素は、 <KeyInfo>
要素の子であり、X509 証明書の 1 つ以上の X509 証明書または識別子を含みます。
<X509Data>
要素内のデータも本質的に信頼されないようにする必要があります。
埋め込み <X509Data>
要素を使用してドキュメントを検証する場合、.NET では、データが X509 証明書に解決され、その公開キーを使用してドキュメント署名を検証できることのみが検証されます。
verifySignatureOnly
パラメーターを false
に設定して CheckSignature メソッドを呼び出すのとは異なり、失効チェックは実行されません。チェーン信頼はチェックされません。また、有効期限も検証されません。 アプリケーションが証明書自体を抽出し、verifySignatureOnly
パラメーターを false
に設定してCheckSignature メソッドに渡しても、ドキュメントの改ざんを防ぐには十分な検証ではありません。 証明書は、署名されているドキュメントに適したものとして検証する必要があります。
埋め込み署名証明書を使用すると、 <X509Data>
セクションでもドキュメント コンテンツでも、便利なキー ローテーション戦略を提供できます。 この方法を使用する場合、アプリケーションは証明書を手動で抽出し、次のような検証を実行する必要があります。
証明書は、アプリケーションにパブリック証明書が埋め込まれている証明機関 (CA) によって直接、またはチェーン経由で発行されました。
既知のサブジェクト名などの追加のチェックなしで OS で提供される信頼リストを使用するだけでは、 SignedXmlの改ざんを防ぐには不十分です。
証明書は、ドキュメント署名時に有効期限が切れていない (ほぼリアルタイムのドキュメント処理の場合は "now" であることが確認されます)。
失効をサポートする CA によって発行された有効期間の長い証明書の場合は、証明書が失効しなかったかどうかを確認します。
証明書のサブジェクトは、現在のドキュメントに適したものとして検証されます。
変換アルゴリズムの選択
特定の値 (XrML など) を指定した仕様と相互運用する場合は、仕様に従う必要があります。 エンベロープ署名がある場合 (ドキュメント全体に署名する場合など)、 http://www.w3.org/2000/09/xmldsig#enveloped-signature ( XmlDsigEnvelopedSignatureTransform クラスで表される) を使用する必要があります。 暗黙的な XML-C14N 変換も指定できますが、必要はありません。 エンベロープ署名またはデタッチされた署名の場合、変換は必要ありません。 暗黙的な XML-C14N 変換は、すべてを処理します。
Microsoft セキュリティ情報 MS16-035 によって導入されたセキュリティにより、.NET では、ドキュメント検証で使用できる変換が既定で制限されており、信頼されていない変換によって、CheckSignatureは常にfalse
返されます。 特に、追加の入力を必要とする変換 (XML で子要素として指定) は、悪意のあるユーザーによる不正使用の影響を受けなくなりました。 W3C では、これらの制限の影響を受ける 2 つの主な変換である XPath 変換と XSLT 変換を回避することをお勧めします。
外部参照に関する問題
アプリケーションが現在のコンテキストに適していると思われる外部参照を検証しない場合、多くのセキュリティ脆弱性 (サービス拒否、分散型リフレクションサービス拒否、情報漏えい、署名バイパス、リモート コード実行など) を提供する方法で悪用される可能性があります。 アプリケーションが外部参照 URI を検証する場合でも、リソースが読み込まれるという問題が 2 回残ります。1 回はアプリケーションが読み取ったとき、1 回は読み取り SignedXml 。 アプリケーションの読み取りとドキュメントの検証の手順に同じコンテンツが含まれているという保証がないため、署名は信頼性を提供しません。
外部参照のリスクを考えると、 SignedXml は外部参照が検出されたときに例外をスローします。 この問題の詳細については、 サポート技術情報の記事3148821を参照してください。
.NET