web-dev-qa-db-ja.com

同じ鍵を使用して署名と暗号化を行う必要がありますか? Azure Training Labsはこのアプローチを採用しています

私はAzureラボを利用しています LoadBalancing with WCF と聞いて、セキュリティの観点からは悪いことだと認識していますが、ここに当てはまるかどうかはわかりません。

誰かがこのコードを見て、本番用コードで異なる証明書を使用する必要があるかどうかを教えてもらえますか?

public class RsaSessionSecurityTokenHandler : SessionSecurityTokenHandler
    {
        public RsaSessionSecurityTokenHandler(X509Certificate2 certificate)
        {
            List<CookieTransform> transforms = new List<CookieTransform>();
            transforms.Add(new DeflateCookieTransform());
            transforms.Add(new RsaEncryptionCookieTransform(certificate));
            transforms.Add(new RsaSignatureCookieTransform(certificate));
            this.SetTransforms(transforms);
        }

        public override ClaimsIdentityCollection ValidateToken(SessionSecurityToken token, string endpointId)
        {
            if (token == null)
            {
                throw new ArgumentNullException("token");
            }
            if (String.IsNullOrEmpty(endpointId))
            {
                throw new ArgumentException("endpointId");
            }

            // in active cases where absolute uris are used check the all parts of the token's 
            // endpoint id and this endpoint's id for equality except the port number
            Uri listenerEndpointId;
            bool listenerHasUri = Uri.TryCreate(endpointId, UriKind.Absolute, out listenerEndpointId);
            Uri tokenEndpointId;
            bool tokenHasUri = Uri.TryCreate(token.EndpointId, UriKind.Absolute, out tokenEndpointId);
            if (listenerHasUri && tokenHasUri)
            {
                if (listenerEndpointId.Scheme != tokenEndpointId.Scheme ||
                    listenerEndpointId.DnsSafeHost != tokenEndpointId.DnsSafeHost ||
                    listenerEndpointId.AbsolutePath != tokenEndpointId.AbsolutePath)
                {
                    throw new SecurityTokenValidationException(String.Format("The incoming token for '{0}' is not scoped to the endpoint '{1}'.", tokenEndpointId, listenerEndpointId));
                }
            }
            // in all other cases, fall back to string comparison
            else if (String.Equals(endpointId, token.EndpointId, StringComparison.Ordinal) == false)
            {
                throw new SecurityTokenValidationException(String.Format("The incoming token for '{0}' is not scoped to the endpoint '{1}'.", token.EndpointId, endpointId));
            }

            return this.ValidateToken(token);
        }
    }
8

多くの人が、暗号化キーと署名キーを分離する理由としてキーエスクローを指摘しています。多くの人は、この特定のケースでは、この鍵の共有使用は問題ないと述べています。しかし、署名と暗号化の両方で鍵を共有する際の暗号の問題については誰も言及していません

暗号化の公式標準を見ると、それらのほとんどは、異なるアルゴリズムに異なる鍵が使用されることを指定しています。 X509証明書の場合、キー使用法の部分には、キーの使用目的に関する非常に具体的な制御があります。そして、例えば、NISTは楕円曲線キーについてこれを言っています:

ECDSAキーshall ECDSAデジタル署名の生成と検証にのみ使用されます。

これは、複数のdifferentアルゴリズムが同じキーで使用されている場合、combinationof allアルゴリズムを1つだけでなく、一緒にそうでない場合、攻撃者はあるアルゴリズムを使用して、別のアルゴリズムのセキュリティを攻撃するために自分では計算できない値を生成する可能性があります。

たとえば、仮に、任意のリモート値に署名する鍵合意プロトコルを使用して、有効な署名を偽造することができます。または、署名する公開鍵を送信すると、鍵合意の攻撃に役立つ値が明らかになる可能性があります。または具体的には、RSAの場合、ifセキュアパディングが使用されなかった場合、署名する値を送信すると、同じ場合に暗号文の復号化が行われます。キーが使用されます。

したがって、署名アルゴリズムと暗号化アルゴリズムの両方が実際に同じキーと一緒に安全に使用できることが確実にveryできない限り、これを行うべきではありません。 。たとえあなたが非常に確信しているとしても、それは悪い暗号の習慣です。そして、あなたが標準に従う必要があるなら、とにかく彼らはあなたを許しません。

5
Nakedible

署名と暗号化では、2つの別々のキーペア(および証明書)を使用することが一般的なベストプラクティスです。私はなぜその理由でリフレッシュしました:

  • キーを暗号化に使用する場合、キーを紛失しても暗号化されたコンテンツが失われないように、エスクローすることがしばしば賢明です。ただし、署名証明書に関連付けられた否認防止は、キーペアの複数のコピーが存在する場合には実行できません。したがって、署名証明書をエスクローする必要はありません。 Wikipedia から

それは私が聞いた中で最高のものです。私が言われることの多くは「ただやる」ことであり、PKIが使用を余儀なくされるPKIの制約内で作業しなければならないことを考えると、それは十分に十分な声明です。

個人的には、単純なPKIで2つを1つにまとめると思います。特に、SSLなどの鍵の「暗号化」機能を使用している場合は、ポイントツーポイント通信に一時的な暗号化を使用しているため、セキュリティリスクはありません。その高い。

ただし、場合によっては、付属のPKIを使用する準備をする必要があります。したがって、暗号化証明書と署名証明書が常に同じであるという仮定をコードがハードコーディングしていた場合、相互運用性の問題があると思います。

最後に、コードについて少し混乱しています。「ValidateToken」がトークンの署名の検証を行うと想定していますよね。同じキーペアを使用して署名を復号化および検証することはできません。暗号化はキーペアホルダーに送信するためのもので、署名はキーペアホルダーからの情報を検証するためのものです。ここで署名検証を行っているだけですか?

6
bethlakshmi

この特定のシナリオでは、この手法は問題ありません。

自己暗号化には、同じ暗号鍵(この場合はX.509証明書)を使用します。あなたが言及するサンプルは、セッショントークン(単純に言えば、保護されたCookie)を実装します。これは、ロードバランサーの背後にある複数の同様のWebサービス間で共有されます。したがって、(この特定のシナリオの)「署名」には、否認防止を提供するというセキュリティ上の目標はありませんが、データの元の認証、つまり基本的にセッショントークンがピアサービスの1つによって作成されたかどうかを把握するというセキュリティ上の目標はありません。

注意:シグネチャが否認防止の目的を果たす他のシナリオでは、別のキーマテリアルを使用する必要があります(ここでの他の回答で正しく指摘されています)。

4
chgeuer

誰かがこのコードを見て、本番コードで異なる証明書を使用する必要があるかどうかを教えてもらえますか?

まず、セキュリティ機能に使用するコードはすべて、本番環境に配置する前に、設計、設計レビュー、実装、コードレビュー、およびテストを行う必要があります。コードがMSDNから提供されたからといって、それが安全であるとは限りません。記述どおりにコードを使用する場合でも、設計をスキップしないでください。この設計は、システム全体の大きな問題に気付くのに役立ちます。

BethlakshmiとRookが指摘したように、証明書は暗号化(機密性)およびデジタル署名(識別と認証)に使用されています。一般に、機能ごとに異なる証明書(またはキー)を使用する必要があります。より簡単に言えば、証明書は1つの機能にのみ使用する必要があります。

この場合、両方の機能に同じ証明書を使用しても問題ありません。操作の1つが失敗してもメッセージが送信される場合でも、RsaEncryptionCookieTransformまたはRsaEncryptionCookieTransformに問題がない限り、証明書の一部が公開されているようには見えません。また、暗号化は成功したが署名はない、または署名はあるが暗号化されていないメッセージを送信しても問題ありません。

両方の機能に1つの証明書を使用する場合は、キー管理計画と脅威モデルでそれを強調表示してください。

3
this.josh

このアプローチに問題はありません。 encryption!=authenticationに注意することが重要です。暗号化を使用しても、メッセージが改ざんされていないことは保証されませんが、メッセージに署名することで、この保証を行うことができます。

1
rook