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