昨日、盗んだ証明書を自分のサーバーに配置し、DNS名が一致するように「Host」ファイルを編集した場合にどうなるかについて、次の質問をしました。
ブラウザーのWebサイトが信頼できるものとして表示されないことがわかりましたが、いくつか質問があります。
「ID」/認証の部分が信頼できるものとして表示される可能性があります(「南京錠」全体が依然として信頼できないものとして表示される場合でも)。 Chromeでは、南京錠>接続をクリックすると、IDと接続の2つの部分があります。 ID部分は認証であり、DNS名が正しかった場合、これは盗まれた証明書で通過すると思いますか?署名はまだ有効であり、変更されていないため、同じ値にハッシュされ、信頼できるエージェントによって署名されていると思います。
上でリンクした質問への回答では、SSL/TLSハンドシェイクを完了するためにサーバー上で秘密鍵が必要であることが接続に信頼できないと表示される理由を説明しています。私の質問は、ハンドシェイクで秘密鍵をどのように使用するかです(あまり深さを探していません)。
RSAまたはDiffie-Hellmanのいずれかを使用して、SSL/TLSで共有対称秘密鍵を作成できますが、実装方法によって異なりますか? RSAで秘密鍵が必要な理由を理解しています。乱数は、サーバーの公開鍵を使用してクライアントによって暗号化され、サーバーに送信され、秘密鍵を使用して復号化されます。証明書を見て公開鍵を見ると、これは常にRSA公開鍵ですか?また、RSAが秘密対称鍵を生成する方法である場合にのみ使用されますか?
RSAの代わりにDHが使用されている場合、これは証明書の公開鍵であるか、または接続が確立されたときに一時的に作成される公開鍵と秘密鍵の両方です。その後、攻撃者のサーバーでSSL/TLS接続を作成できず、盗まれた証明書がサーバーを認証します(DNS名が一致した場合)。
DHがMITM攻撃の影響を受けやすいことを知っているので、認証に証明書が使用されますが、盗まれた証明書が偽のサーバーを認証できる場合、DHとのSSL/TLS接続は、盗まれた証明書を使用して偽のサーバーに起こりますか?
上記の3つの質問の解決にご協力いただければ幸いです。
DHとRSAのどちらを使用するかに関係なく、最初に、サーバーは証明書(サーバーの公開鍵を含む)をHTTPS接続の直後にクライアントに提示します。次に、クライアントとサーバーは、HTTPS接続を容易にするために使用されるSSL/TLSプロトコルと暗号をネゴシエートします。したがって、RSAとDHのどちらを使用するかに関係なく、同じ証明書(つまり、同じサーバー公開鍵)が使用されます。
DHを使用する場合、サーバーはその秘密鍵を使用してデジタル署名を作成し、クライアントはサーバーの証明書からサーバーの公開鍵を使用して検証し、サーバーのIDを認証します。これとは別に、サーバーの秘密鍵と公開鍵は、セッション中は他の目的には使用されません。 DHでは、クライアントとサーバー間でやり取りされるデータの暗号化に使用されるキーは一時的なものです。つまり、キーは1回だけ使用され、再利用されません。この詳細については、 ECDHE_RSA暗号でECDHEがRSAによって署名される方法 を参照してください。ただし、ご覧のように、サーバーが証明書の公開鍵に対応する秘密鍵を持ち、クライアントがサーバーの信頼性を検証するために使用するデジタル署名を作成する必要があります。続行するDH。
RSAを使用する場合、「RSAで秘密鍵が必要な理由がわかります。乱数はサーバーの公開鍵を使用してクライアントによって暗号化され、サーバーに送信されて秘密鍵で復号化されます。」正しい。このセッションキーは、対称暗号化アルゴリズム(AESなど)と共に使用され、クライアントとサーバー間で送受信されるデータを暗号化します。
したがって、RSAとDHのどちらが使用されているかに関係なく、SSL/TLSハンドシェイクを完了してHTTPS接続を確立できるように、サーバーには証明書の公開鍵に対応する秘密鍵が必要です。広く使用されているブラウザは、サイトがHTTPS接続を確立できずに信頼されていることを示しているのではないかと疑っています。
@ mti2935の答えは素晴らしいですが、私はあなたの混乱の性質についていくらかの洞察を持っていると思います。
TLSセッションを介して送信されるデータは、証明書の秘密鍵で暗号化されることはありません。セッションキーで暗号化されています。このセッションキーは、TLSハンドシェイク中に確立されます。どのように重要ではありません。乱数が含まれ、一部は両側から、一部はハッシング、場合によってはDHまたはECDHです。これはすべて簡単で、秘密鍵は必要ありません。
ただし、ハンドシェイクを完了するために、サーバーは、セッションキー交換プロセスの重要な部分を復号化することによって提示した証明書に関連付けられた秘密キーをサーバーが所有していることを証明する必要があります。復号化キーがないと、サーバーはハンドシェイクを完了できず、パイプを介してデータが送信されることはありません。
ほとんどの場合、これは自己署名証明書を使用する場合ほど悲惨なセキュリティ警告をトリガーしません。これは、なんらかのタイプのプロトコルエラーのように見えるか、サーバーがハングしたように見えるためです。そもそもそれが機能する可能性はなかったので、実際には侵入の試みとして扱われていません。
最後に、セマンティクスに関する注意事項:「盗まれた証明書」について語るとき、彼らは通常、盗まれた証明書/秘密鍵のペアを指します。これは、証明書がその性質上公開されているため、証明書自体を盗むことは何もないためです。 Webサーバーはそれらをすべての接続試行に配布し、GoogleのCertificate Transparencyイニシアチブはこれまでに発行されたすべてのものを公開リストに載せることを目指しています。これが問題ない理由は、この攻撃が秘密キーなしでは機能しないためです。
EDIT-OPは実際にはサーバー証明書の使用を意味していました。これを反映して回答が変更されました。主に、最後に追加されたもの
両方の回答(@ mti2935と@MrNerdHair)があなたの質問に対応していますが、コメントの1つは、TLS交換での秘密鍵の使用についてまだ少し混乱していると述べています。私は、TLSプロトコルが高レベルでどのように機能するかを概説することにより、この問題に対処するためのこの回答を提供します。プロトコルの概要の後で、サーバーの秘密鍵の貢献と、パブリック証明書(およびハッキングDNS)だけではWebサーバーを偽造するには不十分である理由を確認できます。
4つのプロトコル(RSA、Diffie-Hellman、およびTLSが各プロトコルをどのように使用するか)を調べてみましょう。まず、すべてのネットワーク暗号化確立プロトコルは、対称暗号化に使用される秘密セッションキーの作成で終わります。これはエンジニアリングの原則であり、セキュリティの原則ではありません。どうして?対称暗号化は高速になるように設計されていますが、他の形式の暗号化(RSA)は低速であり、一部の鍵合意プロトコルには暗号化がありません。プロトコル2、3、および4は、双方がセッションキーに安全に同意する方法を示しています。
RSA公開鍵暗号化は、一方向暗号化または双方向暗号化です。ただし、交換のどちらの当事者も、交換の前に相手と会って秘密を交換する必要がないという点で、対称暗号とは異なります。一方向の暗号化に焦点を当てて、何か(メッセージやキーなど)を暗号化して送信するにはどうすればよいですか?
クライアントがシークレットメッセージをサーバーに送信する方法を次に示します。
Client to Server: Hello
Server to Client: Hello, Cert_Server
Client, internal: Somehow Validate Cert_Server and, if valid,
Client to Server: Enc(plaintext, Key_Public)
Server, internal: Dec(cryptext, Key_Private)
それだけです。クライアントはプレーンテキストを暗号化してサーバーに送信しました。誰もが暗号解読(Enc(msg, key_pub)
)を見ることができますが、Nを因数分解したり、サーバーの秘密鍵(素数pとqを知って計算されたd)を盗んだりして、RSAを破ることなくサーバーだけが平文を見ることができます。サーバーは、秘密鍵(d、N)を使用して復号化することにより、平文を見ることができます。クライアントの検証手順には、証明書が内部で有効であることの確認(すべての署名のチェックアウト)、ルートCAの確認、失効リストの確認が含まれます。
簡単に言えば、DHキー交換では、2つの数値(P、g)から始めます。Pは素数(実際には安全素数で、P = 2Q + 1でQも素数)であり、gはジェネレーターです。
交換は次のようになります。
Client to Server: Hello
Server to Client: Hello, (g,P)
Client, internal: A = RND(P), a = (g^A)%P
Client to Server: a
Server, internal: B = RND(P), b = (g^B)%P, K = (a^B)%P
Server to Client: b
Client, internal: K=(b^A)%P
交換の終わりに、両当事者はKを知っていますが、(g、P、a、b)を含む交換を監視している誰も、フィールドPで離散対数を実行することができなければKを計算できません。
これは中間者攻撃の対象となることに注意してください。 (g、P)がわかっているため(サーバーから送信されます)。つまり、Malloryは途中でクライアントとのサーバー側の交換を実行し、サーバー側との交換のクライアント側を実行して、2個別の秘密(K)を生成でき、どちらの側もそれを行いませんマロリーが真ん中に座っていることを知っています。
RSAのみを使用するTLS暗号スイートは、次のように機能します(他の多くのビットは省略されます)。
Client to Server: Hello
Server to Client: Hello, Cert_Server
Client, internal: Somehow Validate Cert_Server and, if valid,
Client, internal: K=RND()
Client to Server: Enc(K, Key_Public)
Server, internal: Dec(cryptext, Key_Private)
これは、上記のRSAの説明と基本的に同じですが、プレーンテキストの場合はクライアント生成のセッションキーKを使用していることに注意してください。TLS_RSA暗号スイートの問題の一部は、クライアントがKを生成することです。 、クライアントはK(暗号学的に強力なRNG)を生成するのに十分な仕事をしていないため、セッションは攻撃にさらされたままです。
DH_RSAのTLS暗号スイート(多くのビットが切り取られているため、順序がわずかに壊れている可能性があります):
Client to Server: Hello
Server, internal: B=RND(P), b=(g^B)%P
Server to Client: Hello, Cert_Server, g, P, Sign({b}, Key_Private)
Client, internal: Somehow Validate Cert_Server and, if valid,
Client, internal: A = RND(P), a = (g^A)%P, K = (b^A)%P
Client to Server: a
Server, internal: K=(a^B)%P
ここでは、両方のプロトコルをマージしています。サーバーからDHエフェメラルbに署名することにより、DH Key Exchangeが被るMITM攻撃を修正します。次に、クライアントとサーバーはDHキー交換を使用して、セッションキーKを生成します。
わかりました。その長い間が経た後、サーバーの証明書とDNSハックを使用して(セキュリティで)正規のWebサイトを偽造することはどうでしょうか。
前に戻って、上記の4つのプロトコルの説明のうち3つでPrivate_Keyを探します。いずれの場合も、サーバーがメッセージを解読するか、メッセージを使用して署名していることがわかります。したがって、攻撃者がサーバーの秘密キーを盗んだ場合を除き、攻撃者はこれらの各プロトコルのサーバー側を実行してそのサーバーを偽装することはできません。クライアントはいくつかの方法でサーバーの障害を検出できます。以下のアルゴリズムの各検出について詳しく説明します。
Sign(b, Key_Private)
ステップに注意してください。秘密鍵のない偽のサーバーはこの署名を実行できなかったため、クライアントはその時点で(チェックする必要があるため)サーバーが偽であることを認識します。しかし、ここには攻撃があります。攻撃者はこの暗号スイートを実サーバーで実行でき、署名済みの一時的なデータを送信します。つまり、偽のサーバーはSign(b_old, Key_private)
のコピーを(一度だけ必要な)フェッチできます。クライアントは署名を検証し、すべてが正常に見えます。これが、クライアントmustが生成されたセッションキーを使用して最終的にサーバーを認証する理由です。最後に、キーの相互証明のサンプルクライアントとサーバーの相互認証:
... continuing exchange ...
Client, internal: K_enc = F1(K), K_mac = F2(K), Nc = NONCE
Client, internal: Ec = Enc(Nc, K_enc), Hc = HMAC(Nc, K_mac)
Client to Server: Ec, Hc
Server, internal: K_enc = F1(K), K_mac = F2(K), Ns = NONCE
Server, internal: Hc == HMAC(Dec(Ec, K_enc), K_mac)?
Server, internal: Es = Enc(Ns||Nc, K_enc), Hs = HMAC(Ns||Nc, K_mac)
Server to Client: Es, Hs
Client, internal: Hs == HMAC(Dec(Es, K_enc), K_mac)?
次のような2つの内部ステップに注意してください。1つはサーバー用、もう1つはクライアント用です。Hs == HMAC(Dec(Es, K_enc), K_mac)?
これは、サーバーがセッションキーを知っていることを証明するためにクライアントが実行する数学的証明であり、暗号化とhmacキー、およびそれが送信した(Nsに連結されたサーバー)ナンス、Ncを復号化することができました。
この特定のチェックは次のように分類されます。
これらの手順はすべて、以前に行われたさまざまな手順の証明であり、サーバーがクライアントに正当であることを証明できます。
それがあなたの質問に答えることを願っています。