トランスポート・レイヤー・セキュリティ(TLS)は、Webで暗号化を実装する場合に最もよく使用されるプロトコルです。 TLSは、ネットワークでセキュアな通信を行うために暗号化プロセスを組み合わせて使用します。 このセクションでは、TLSおよびTLSが使用する暗号化プロセスについて簡単に説明します。
TLSは、インターネット通信で使用される標準的なTCP/IPソケットプロトコルをセキュアに拡張します。 表「TCP/IP TLSを使用したプロトコル・スタック」に示すように、トランスポート・レイヤーとアプリケーション・レイヤーの間に、標準のTCP/IPプロトコル・スタックのsecure sockets layerが追加されます。 TLSとともにもっともよく使用されるアプリケーションは、インターネットWebページ用のプロトコルであるHypertext Transfer Protocol (HTTP)です。 この他にも、Net News Transfer Protocol (NNTP)、Telnet、Lightweight Directory Access Protocol (LDAP)、Interactive Message Access Protocol (IMAP)、File Transfer Protocol (FTP)などのアプリケーションがあり、同様にTLSとともに使用します。
TLSを使用するTCP/IPプロトコル
TCP/IPの層 | プロトコル |
---|---|
アプリケーション層 | HTTP、NNTP、Telnet、FTPなど |
Transport Layer Security | TLS |
伝送制御プロトコル | TCP |
インターネット層 | IP |
Secure Socket Layer (SSL)は、1994年にNetscape社によって開発され、インターネットの世界で使用されるようになると、標準的な存在になりました。 現在では、国際的な標準化機構であるInternet Engineering Task Force (IETF)が管理しています。 IETFはSSLの名称をTLSに変更し、1999年1月に最初の仕様のバージョン1.0をリリースしました。 TLS 1.0は、SSLの最新バージョン3.0を少しだけ変更したものです。 このアップグレードでは、前のバージョンでの不具合が修正され、既知の弱いアルゴリズムの使用が禁止されました。 TLS 1.1は2006年4月、TLS 1.2は2008年8月、TLS 1.3は2018年8月にリリースされました。 TLS 1.3はTLSプロトコルを全面的に見直したもので、以前のバージョンよりもセキュリティとパフォーマンスが大幅に向上しています。
TLSが有効な理由の1つに、複数の暗号化プロセスを使用していることがあります。 TLSは、公開キー暗号化で認証を行い、秘密キー暗号化とハッシュ関数で機密性とデータ整合性を提供します。 TLSについて理解する前に、暗号化の処理方法を理解しておくと役立ちます。
暗号化の主な目的は、2者間の秘密の通信に権限のない第三者がアクセスしたり、その内容を理解するのを困難にすることです。 暗号化のプロセスによって、データに対する権限のないすべてのアクセスを必ずしも制限できるわけではありませんが、権限のない者が秘密のデータを理解できないようにすることができます。 暗号化では、複雑なアルゴリズムを使用して、元のメッセージ(クリアテキスト)をエンコードされたメッセージ(暗号テキスト)に変更します。 ネットワーク上で転送されるデータの暗号化および復号化に使用するアルゴリズムは一般に、秘密キー暗号化と公開キー暗号化の2つのカテゴリに分けられます。
秘密キー暗号化も公開キー暗号化も、合意に基づく暗号キーまたは暗号キーのペアを使用します。 キーは、データの暗号化プロセスおよび復号化プロセスで暗号化アルゴリズムが使用するビット文字列です。 暗号化キーは、錠のキーと同様、錠を開けることができるのは正しいキーのみです。
通信の当事者が互いにキーを安全に送信するのは、些細な問題ではありません。 公開キー証明書を使用すると、公開キーを安全に送信し、受信者に公開キーの信頼性を保証できます。 「公開鍵証明書」を参照してください。
秘密キー暗号化と公開キー暗号化における暗号化処理の説明では、セキュリティのコミュニティで広く使用されている慣例(通信する2人の当事者はAliceとBobという名前で示される)に従います。 権限のない第三者は攻撃者とも呼ばれ、Charlieと名付けられます。
秘密キー暗号化では、通信するAliceとBobはメッセージの暗号化と復号化に同じキーを使用します。 暗号化されたデータをネットワークで送信する前に、AliceとBobはキーを持っていることが必要で、暗号化と復号化に使用する暗号化アルゴリズムに同意している必要があります
秘密キー暗号化で大きな問題の1つが、攻撃者にアクセスされずに一方から他方にキーを渡す方法の問題です。 AliceとBobが秘密キー暗号化でデータを保護しても、CharlieがそのキーにアクセスできればAliceとBobの間で傍受した秘密メッセージを理解できます。 CharlieはAliceとBobのメッセージを復号化できるだけではなく、Aliceになりすまして暗号化データをBobに送信することもできるのです。 ボブはメッセージがアリスではなくチャーリから来たことを知りません。
秘密鍵配布の問題が解決された後、秘密鍵暗号は貴重なツールとなり得る。 そのアルゴリズムにより、優れたセキュリティと暗号化データが比較的迅速に提供できるからです。 TLSセッションで送信される機密性の高いデータの多くは、秘密キー暗号化で送信されます。
秘密キー暗号化は、データの暗号化と復号化の両方に同じキーを使用するため、対称暗号化とも呼ばれます。 よく知られている秘密キー暗号化アルゴリズムには、Advanced Encryption Standard (AES)、Triple Data Encryption Standard (3DES)およびRivest Cipher 4 (RC4)があります。
公開キー暗号化は、公開キーと秘密キーの両方を使用することでキーの配布方法の問題を解決しました。 公開キーはネットワークを通じて公開し、送信できますが、非公開キーは通信の1人の当事者にしか公開されません。 公開キーと非公開キーは暗号化方式が逆で、一方のキーで暗号化したものをもう一方のキーで復号化します。
Bobが公開キー暗号化を使用して、Aliceに秘密のメッセージを送信するとします。 Aliceは公開キーと非公開キーをどちらも持っているので、非公開キーは安全な場所に保管しておき、公開キーをBobに送信します。 BobはAliceの公開キーを使ってAliceへの秘密のメッセージを暗号化します。 Aliceは非公開キーを使ってメッセージを復号化します。
Aliceが自分の秘密キーを使用してメッセージを暗号化し、その暗号化されたメッセージをBobに送信すれば、Bobが受信するデータはAliceから届いたものだと考えることができます。BobがAliceの公開キーでデータを復号化できれば、そのメッセージはAliceが自分の秘密キーで暗号化したものに間違いなく、Aliceの秘密キーを持っているのはAliceのみです。 問題は、Aliceの公開キーが公開されているために、だれもがメッセージを読めてしまうことです。 このシナリオは、セキュアなデータ通信を考慮に入れていませんが、デジタル署名の基本を示しています。 デジタル署名とは公開キー証明書のコンポーネントの1つで、TLSでクライアントやサーバーを認証するために使用します。 公開キー証明書とデジタル署名を参照してください。
公開キー暗号化は、データの暗号化および復号化に様々なキーが使用されるため、asymmetric cryptography
とも呼ばれます。 TLSでよく使われる、よく知られている公開キー暗号化アルゴリズムは、Rivest Shamir Adleman (RSA)アルゴリズムです。 このほかにも、秘密キーを交換するために設計されたTLSを使う公開キー暗号化アルゴリズムには、Diffie-Hellman (DH)があります。 公開キー暗号化には膨大な計算が必要なため、速度が大幅に遅くなります。 そこで、この方式は暗号化データ通信全体に使用するよりもむしろ、秘密キーなど少量のデータを暗号化する場合にだけ使用します。
秘密キー暗号化と公開キー暗号化のどちらにも、長所と短所があります。 秘密キー暗号化では、データの暗号化や復号化に時間はかかりませんが、通信者同士が同じ秘密キー情報を共有する必要があり、キーの交換の方法が問題になります。 公開キー暗号化では、キーを秘密にする必要がないのでキーの交換は問題になりませんが、データの暗号化と復号化に使用するアルゴリズムには膨大な計算が必要で、著しく遅くなります。
公開キー証明書を使用すると、エンティティは非対称暗号化で使用する公開キーを安全に配布できます。 公開キー証明書は、次の状況を回避します。Charlieが自分の公開キーと秘密キーを作成すれば、自分はAliceだと名乗ってBobに公開キーを送信できます。 BobはCharlieと通信できますが、データをAliceに送信していると思い込んでしまいます。
公開キー証明書は電子的なパスポートだと考えることができます。 これは、信頼できる組織によって発行され、所有者に識別情報を提供します。 公開キー証明書を発行する信頼できる組織を、証明書発行局(CA)と呼びます。 CAは公証人にたとえることができます。 CAから証明書を取得するには、識別情報の証拠となるものを提供する必要があります。 CAは、申請者が申し立てる組織の代表であるとの確証が得られたら、証明書に含まれる情報の妥当性を証明する証明書に署名します。
公開キー証明書には、次のようなフィールドがあります。
ボブが公開鍵証明書でアリス公開鍵を有効なものとして受け入れた場合、チャールズがアリスとして偽装したときにボブは秘密情報をチャーリに送信することに騙されません。
複数の証明書を証明書チェーンでリンクすることもできます。 証明書チェーンを使用する場合、最初の証明書は必ず送信者の証明書です。 次は送信者の証明書を発行したエンティティの証明書です。 チェーン内に他の証明書がある場合、それぞれ直前の証明書を発行した証明書発行局の証明書です。 チェーンの最後の証明書は、ルートCAの証明書です。 ルートCAは広く信頼されているパブリック認証局です。 複数のルートCAの情報は、通常、クライアントのインターネット・ブラウザに保存されています。 この情報には、CAの公開キーが含まれています。 よく知られているCAには、Comodo、DigiCertおよびGoDaddyなどがあります。
暗号化されたデータを送信する場合、TLSは通常、暗号化ハッシュ関数を使ってデータの整合性を保証します。 ハッシュ関数を使って、AliceがBobに送ったデータをCharlieが改ざんできないようにします。
暗号化ハッシュ関数はチェックサムに似ています。 主な違いは、チェックサムがデータの偶発的変化を検出するのに対し、暗号化ハッシュ関数は故意による変更を検出するように設計されています。 暗号化ハッシュ関数によってデータが処理されると、hash
と呼ばれる小さなビット文字列が生成されます。 メッセージがごくわずかだけ変更された場合も、結果として生成されるハッシュは大きく変更されます。 暗号化ハッシュ関数には、暗号化キーが必要ありません。 TLSとともによく使用されるハッシュ関数は、Secure Hash Algorithm (SHA)です。 SHAは、U.S. National Institute of Standards and Technology (NIST)によって提案されました。
メッセージ認証コード(MAC)は暗号化ハッシュに似ていますが、秘密キーをベースにしている点が異なります。 秘密キー情報が暗号化ハッシュ関数で処理したデータに含まれている場合、その結果生成されるハッシュはHMACと呼ばれます。
Aliceは、BobへのメッセージをCharlieが確実に改ざんしないようにする場合、メッセージのHMACを計算して元のメッセージにHMACを追加できます。 次に、Bobと共有している秘密キーを使用してメッセージとHMACを暗号化できます。 Bobは、メッセージを復号化してHMACを計算すれば、送信中にメッセージが変更されたかどうかを知ることができます。 TLSでは、HMACを使ってセキュアなデータを送信します。
メッセージに暗号化ハッシュが作成されると、ハッシュは送信者の非公開キーで暗号化されます。 このような暗号化ハッシュをデジタル署名と呼びます。
TLS 1.3を使用した通信によってTLSハンドシェークが開始されます。 これは、クライアントとサーバー間の初期ネゴシエーションで、TLS内で以降の相互作用のパラメータを確立します。 これは、キー交換、サーバー・パラメータおよび認証という3つのフェーズで構成されます:
Key Exchange
: このフェーズでは、共有キーが(楕円曲線グループ (ECDHE)または有限フィールド・グループ (DHE))に属することができる名前付きグループなどの共有キーイング・マテリアルを確立し、対称暗号オプションなどの暗号化パラメータを選択します。
Server Parameters
: このフェーズでは、証明書ベースのクライアント認証が必要かどうかなど、その他のハンドシェイク・パラメータが確立されます。
Authentication
: このフェーズでは、サーバー(オプションで、クライアント)を認証し、キー確認およびハンドシェイク整合性を提供します。
次の図に、TLSハンドシェーク全体の一連のメッセージを示します。
キーの交換:
クライアントは、サーバーにClientHelloメッセージを送信します。
サーバーはClientHelloメッセージを処理し、接続に適した暗号化パラメータを決定します。 その後、ネゴシエーションされた接続パラメータを示す独自のServerHelloメッセージで応答します。 TLS 1.3の場合、ServerHelloメッセージによってキーおよび暗号オプションのみが決定されます。 その他のハンドシェーク・パラメータは、後で決定できます。
サーバー・パラメータ: サーバーは、次の2つのメッセージを送信してサーバー・パラメータを確立します:
EncryptedExtensions: このメッセージには、個々の証明書に固有のものを除いて、暗号化パラメータの決定に必要とされないClientHello拡張への応答が含まれています。
CertificateRequest (オプション): 証明書ベースのクライアント認証が必要な場合、サーバーはその証明書に必要なパラメータを含むメッセージを送信します。 クライアント認証が不要な場合、このメッセージは省略されます。
認証:
サーバーは次の認証メッセージを送信します:
Certificate (オプション): このメッセージには、認証証明書と、証明書チェーン内のサポートするその他の証明書が含まれます。 サーバーが証明書で認証されていない場合、このメッセージは省略されます。
ノート: 証明書メッセージには、証明書のかわりにRAWキーを含めることができます。
CertificateVerify (オプション): このメッセージには、Certificateメッセージ内の公開キーに対応する秘密キーを使用したハンドシェーク全体に対する署名が含まれています。 サーバーが証明書で認証されていない場合、このメッセージは省略されます。
Finished: ハンドシェーク全体のMAC (メッセージ認証コード)。
クライアントは、独自のCertificate、CertificateVerifyおよびFinishedメッセージで応答します。 サーバーがCertificateRequestメッセージを送信しなかった場合、Certificateメッセージは省略されます。 クライアントが証明書で認証されていない場合、CertificateVerifyメッセージは省略されます。
クライアントとサーバーは、アプリケーション・データを相互に安全に送信できるようになりました。
キー交換メッセージ、ClientHelloおよびServerHelloは、クライアントとサーバーのセキュリティ機能を決定し、残りのハンドシェークおよびアプリケーション・データの保護に使用されるトラフィック・キーを含む共有シークレットを確立します。
ClientHello
TLSハンドシェークは、クライアントがClientHelloメッセージをサーバーに送信することから始まります。 このメッセージには次のフィールドがあります:
ノート: TLSメッセージには、ここにリストされているフィールド以外のフィールドが含まれる場合があります。TLSメッセージとそのフィールドの詳細は、TLS 1.3の指定を参照してください。
cipher_suites
: このフィールドには、クライアントでサポートされている対称暗号オプションのリスト、特にレコード保護アルゴリズム(秘密キーの長さを含む)およびキー・ハッシュ・メッセージ・コード(HMAC)ベースの抽出および拡張キー導出関数(HKDF)で使用されるハッシュが含まれます。
extensions
: 拡張機能は、既存のクライアントへの影響を最小限に抑えながら、TLSプロトコルへの新機能の追加を容易にします。 ClientHelloメッセージには次の拡張機能が含まれる場合がありますが、これらに限定されるわけではありません:
supported_versions
: この拡張機能は、クライアントがサポートするTLSのバージョンを示します。 ClientHelloメッセージにこのメッセージが含まれている必要があります。
status_request
: この拡張は、クライアントが証明書ステータス・プロトコルを使用する必要があることを示します。サーバーは、証明書ステータス・プロトコルを使用することに同意しない場合があります。 証明書ステータス・プロトコルの例として、オンライン証明書ステータス・プロトコル(OCSP)があります。 クライアント主導型OCSPとOCSPステープリングを参照してください。
supported_groups
: この拡張は、クライアントがキー交換をサポートしている名前付きグループを示します。 これらの名前付きグループには、楕円曲線(ECDHE)グループと有限フィールド(DHE)グループが含まれます。 ECDHEまたはDHEキー交換を使用している場合、ClientHelloメッセージにはこのメッセージが含まれている必要があります。
key_share
: この拡張には、キー交換用の暗号化パラメータのリストが含まれています。 client_sharesという名前のフィールドに、このリストが格納されています。 このリストの各項目には、次のフィールドが含まれています:
group
: キー交換暗号化メソッドの基になるグループの名前。 JDKプロバイダ・ドキュメントのSunJSSEプロバイダを参照してください。
key_exchange
: キー交換情報。グループ・フィールドの値によって決まります。
pre_shared_key
: 事前共有キー(PSK)は、使用する前にいくつかのセキュア・チャネルを使用して2つのパーティ間で以前に共有された共有シークレットです。 PSKは、以前の接続で確立し、新しい接続の確立に使用できます。 ハンドシェークが完了すると、サーバーは、初期ハンドシェークから派生した一意のキーに対応するPSK IDをクライアントに送信できます。 事前共有キーを使用したセッション再開を参照してください。
cookie
: サーバーがHelloRetryRequestメッセージを送信すると、この拡張をクライアントに含めることができます。 (受入れ可能なパラメータ・セットが見つかった場合、サーバーはClientHelloメッセージに応答してHelloRetryRequestメッセージを送信しますが、ハンドシェークを続行するための十分な情報がClientHelloメッセージにありません。) この拡張機能の目的の1つは、サーバーがクライアントに見かけのネットワーク・アドレスでの到達可能性を示すことを強制できるようにすることです(これにより、サービス拒否攻撃(DoS)保護が提供されます)。 クライアントは、新しいClientHelloメッセージを送信するときに、HelloRetryRequestで受信したコンテンツをこの新しいClientHelloメッセージのCookie拡張にコピーする必要があります。
server_name
: TLS 1.3は、クライアントが接続しているサーバーの名前をサーバーに通知するメカニズムを提供しません。 クライアントは、この拡張機能を使用してこの情報を提供することで、単一のネットワーク・アドレスで複数の仮想サーバーをホストするサーバーへ容易に接続できます。 一部のサーバーでは、クライアントがこの拡張機能を送信する必要がある場合があります。
ServerHello
受け入れ可能なハンドシェーク・パラメータのセットをネゴシエートできる場合、サーバーはServerHelloメッセージでクライアントのClientHelloメッセージに応答します。 このメッセージには次のフィールドがあります:
cipher_suite
: このフィールドには、ClientHello.cipher_suitesフィールドのリストからサーバーによって選択された単一の暗号スイートが含まれます。
extensions
: このフィールドには、暗号contextを確立し、プロトコル・バージョンをネゴシエートするために必要な拡張機能が含まれています。 SeverHelloに含まれる可能性のある拡張機能には、次のものがあります:
supported_versions
: 使用しているTLSのバージョンを示します。 ServerHelloメッセージには、この拡張機能が含まれている必要があります。
key_share
: この拡張には、キー交換用の暗号化パラメータのリストが含まれています。
pre_shared_key
: この拡張には、サーバーが使用することに同意した事前共有キーが含まれています。 事前共有キーの詳細は、 事前共有キーを使用したセッション再開を参照してください。
サーバーは、EncryptedExtensionsメッセージで他の拡張機能を個別に送信します。
サーバーは、ServerHelloメッセージをクライアントに送信した後、EncryptedExtensionsとCertificateRequestの2つのメッセージを送信してサーバー・パラメータを確立します:
EncryptedExtensions: このメッセージには、個々の証明書に固有の暗号化パラメータ以外の暗号化パラメータの決定に必要ないClientHello拡張機能へのレスポンスが含まれています。
CertificateRequest: 証明書ベースのクライアント認証が必要な場合は、このメッセージが送信されます。 これには、クライアントからリクエストされた証明書のパラメータが含まれます。 次のフィールドが含まれます。
certificate_request_context
: このフィールドには、証明書リクエストを識別する識別子が含まれます
extensions
: このフィールドには、リクエストされた証明書のパラメータを説明する拡張機能が含まれています。 次の拡張機能が含まれる場合があります:
signature_algorithms
: この拡張機能は、CertificateVerifyメッセージで使用できるシグネチャ・アルゴリズムを示します。 ServerHelloメッセージには、この拡張機能が含まれている必要があります。
signature_algorithms_cert
: この拡張機能は、デジタル・シグネチャで使用できるシグネチャ・アルゴリズムを示します。 このメッセージが送信されない場合は、signature_algorithms拡張で指定された値が使用されます。
certificate_authorities
: この拡張は、サーバーが受け入れる認証局を示します。
supported_groups
: このメッセージには、サーバーが優先する名前付きグループが含まれます。 クライアントは、この情報を使用して、後続の接続でkey_share拡張で使用するグループを変更できます。
TLSハンドシェークでサーバーとクライアントが相互に送信する最後の3つのメッセージは、Certificate、CertificateVerifyおよびFinishedです。
証明書
このメッセージには、認証証明書と、証明書チェーン内のサポートするその他の証明書が含まれます。 キー交換方法で認証に証明書を使用する場合、サーバーはこのメッセージを送信する必要があります。 サーバーがCertificateRequestメッセージを介してクライアント認証をリクエストした場合にのみ、クライアントはこれを送信する必要があります。 Certificateメッセージには、次のフィールドが含まれます:
certificate_list
: このフィールドには一連のCertificateEntry構造体が含まれ、それぞれに単一の証明書と一連の拡張が含まれます
extensions
: 証明書メッセージに含まれる拡張子は次のとおりです:
status_request
: クライアント駆動型OCSPおよびOCSPステープリングを参照してください
signed_certificate_timestamp
: TLSクライアントは、証明書がログに記録されないかぎり、証明書を受け入れません。 有効な証明書がログに送信されると、ログは署名付き証明書タイムスタンプ(SCT)を返す必要があります。RFC 6962: Certificate Transparencyを参照してください。
CertificateVerify
このメッセージには、Certificateメッセージ内の公開キーに対応する秘密キーを使用したハンドシェーク全体に対する署名が含まれています。 クライアントまたはサーバーが証明書に対応する秘密キーを持っていることを証明します。 このメッセージには次のフィールドが含まれます:
algorithm
: このフィールドには、使用されるシグネチャ・アルゴリズムが含まれます。 サポートされているアルゴリズムについては、 JDKプロバイダ・ドキュメントの SunJSSEプロバイダを参照してください。
signature
: このフィールドには、アルゴリズムを使用したデジタル・シグネチャが含まれます。
Finished
このメッセージには、ハンドシェーク全体に対するMessage Authentication Code (MAC)が含まれています。 クライアントとサーバーがそれぞれのピアから受信したFinishedメッセージを検証すると、両側が接続を介してアプリケーション・データを送受信できるようになります。
事前共有キー(PSK)は、使用する前になんらかのセキュアなチャネルを使用している2者間で共有されていた共有シークレットです。 あるTLSハンドシェーク中にPSKを確立し、それを使用して別のハンドシェークで新しい接続を確立できます。これはPSKによるセッション再開と呼ばれます。 PSKは、初期ハンドシェークから導出された一意のキーに対応します。 新しい接続の確立時にサーバーがPSKを受け入れる場合、この接続のセキュリティ・コンテキストは暗号により元の接続に関連付けられ、完全なTLSハンドシェークではなく、最初のハンドシェークから導出されたキーを使用して暗号化状態がブートストラップされます。
次の図は、2つのハンドシェークを示しています。1つ目はPSKを確立し、もう1つはPSKを使用します。
PSKを確立するTLS 1.3ハンドシェイク
PSKを使用するTLS 1.3ハンドシェイク
クライアントは、key_share拡張を含むClientHelloメッセージをサーバーに送信します。 この拡張機能は、クライアントがサポートするキー交換暗号化方式を一覧表示します。
サーバーは、key_share拡張を含むServerHelloメッセージで応答します。 この拡張機能には、キー交換に使用する暗号化方式が含まれています。
サーバーはそのサーバー・パラメータをクライアントに送信します。
サーバーとクライアントの両方が認証メッセージを交換します。
サーバーはNewSessionTicketメッセージをクライアントに送信します。このメッセージにはPSKが含まれており、クライアントはこのPSKをClientHelloメッセージのpre_shared_key拡張に含めることで、将来のハンドシェークに使用できます。
クライアントとサーバーは、暗号化されたアプリケーション・データを交換できるようになりました。
将来のハンドシェークでは、クライアントは、key_shareおよびpre_shared_key拡張を含むClientHelloメッセージをサーバーに送信します。 pre_shared_key拡張には、NewTicketSessionメッセージで送信されるPSKが含まれています。
サーバーは、pre_shared_keyおよびkey_share拡張を含むServerHelloメッセージで応答します。 pre_shared_key拡張には、サーバーが使用に同意したPSKが含まれます。
サーバーはそのパラメータをクライアントに送信します。
サーバーとクライアントは、互いにFinishedメッセージを送信します。 この接続のセキュリティ・コンテキストは暗号により元の接続に結び付けられるため、認証フェーズは実行されません。
クライアントとサーバーは、暗号化されたアプリケーション・データを交換できるようになりました。
ノート: JDK 8では、次の機能はサポートされていません:
PSKのみを使用した再開: PSKを(EC) DHEキー交換とともに使用する必要があります。これにより、前方秘匿性が共有キーと組み合せて提供されます。 PSKのみを使用した再開は、前方秘匿性および後方秘匿性に関して安全性が低くなります。
ラウンドトリップ時間ゼロの再開(0-RTT): これにより、クライアントとサーバーは最初のメッセージ(ClientHelloとServerHello)のアプリケーション・データを相互に送信できます。 クライアントはPSKを使用して、最初にClientHelloで送信するアプリケーション・データを暗号化し、サーバーを認証します。 これには、PSKのみを使用した再開およびリプレイ攻撃の可能性があるというセキュリティ上の問題があります。
ステートレス・サーバーPSK: 「RFC5077: Transport Layer Security (TLS) Session Resumption without Server-Site State」では、サーバーがセッションを再開し、クライアントごとのセッション状態を維持しないようにするメカニズムについて説明しています。 このメカニズムを使用すると、PSKのみを使用した再開のための前方秘匿性を犠牲にして、サーバーのメモリー使用量が減少します。
帯域外PSKの確立: これは、NewSessionTicketメッセージ以外を使用したPSKの生成を意味します。
クライアントとサーバーは、ハンドシェーク後に他のメッセージ(新規セッション・チケット・メッセージ、ポストハンドシェーク認証およびキー更新)を送信できます。
Finishedメッセージの受信後にサーバーによって送信されるNewSessionTicketメッセージには、クライアントが将来のハンドシェークに使用できる事前共有キーが含まれています。 事前共有キーを使用したセッション再開を参照してください。
クライアントがpost_handshake_auth拡張を送信した場合、サーバーはハンドシェーク後いつでもCertificateRequestメッセージを送信してクライアント認証をリクエストできます。 クライアントが認証を受ける場合は、Certificate、CertificateVerifyおよびFinishedメッセージを送信する必要があります。 クライアントが拒否した場合は、証明書を含まないCertificateメッセージおよびFinishedメッセージを送信する必要があります。
KeyUpdateハンドシェーク・メッセージは、送信者が送信暗号キーを更新していることを示すために使用されます。 これはTLS 1.2のChangeCipherSpecメッセージを置き換えます。
jdk.tls.keyLimits
セキュリティ・プロパティを使用して、アルゴリズムが特定のキー・セットで暗号化できるデータの量に制限を指定できます。 アルゴリズムでキー・セットを使用して暗号化可能なデータ量の制限を参照してください。
この項では、JSSEの機能拡張によって生じる可能性がある互換性の問題やその他の既知の問題について説明します。
TLS 1.3には以前のバージョンとの直接的な互換性がない
TLS 1.3には、以前のバージョンとの直接的な互換性がありません。 TLS 1.3を下位互換性モードで実装することは可能ですが、TLS 1.3にアップグレードする際に考慮する互換性リスクはまだいくつかあります。
TLS 1.3ではhalf-closeポリシーを使用し、TLS 1.2以前ではduplex-closeポリシーを使用しています。 duplex-closeポリシーに依存しているアプリケーションでは、TLS 1.3へのアップグレード時に互換性の問題が発生する場合があります。
signature_algorithms_cert拡張では、証明書認証に事前定義済の署名アルゴリズムを使用することが求められます。 しかし実際には、サポートされていない署名アルゴリズムがアプリケーションで使用されている場合があります。
DSA署名アルゴリズムはTLS 1.3ではサポートされていません。 サーバーがDSA証明書のみを使用するように構成されている場合、サーバーではTLS 1.3接続をネゴシエートできません。
TLS 1.3でサポートされている暗号化方式群は、TLS 1.2以前のものとは異なります。 サポートされなくなった暗号化方式群がアプリケーションでハードコードされている場合、コードを修正せずにTLS 1.3を使用することはできない場合があります(たとえばTLS_AES_128_GCM_SHA256 (1.3以降)とTLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (1.2以前))。
TLS 1.3のセッション再開およびキー更新の動作はTLS 1.2以前とは異なります。 互換性の影響はわずかですが、アプリケーションがTLSプロトコルのハンドシェークの詳細に依存している場合にはリスクになる可能性があります。
SSLを使った通信は、クライアントとサーバー間の情報交換から始まります。 この情報交換をSSLハンドシェークと呼びます。 SSLハンドシェークには、次のステージがあります。
SSLセッションは、どの暗号群を使用するかについて、クライアントとサーバーがネゴシエーションを行うことから始まります。 cipher suite
は、コンピュータがデータの暗号化に使用できる一連の暗号化アルゴリズムおよびキー・サイズです。 符号化方式には、公開キー交換アルゴリズムまたはキー合意アルゴリズム、および暗号化ハッシュ関数に関する情報が含まれます。 クライアントは利用できる暗号群をサーバーに伝え、サーバーは、どちらにも適用できる暗号群を選択します。
SSLの認証ステップはオプションです。しかし、Web上の電子商取引の例では、一般にクライアントがサーバーを認証します。 サーバーの認証により、サーバーが表すとクライアントが信じているエンティティを、そのサーバーが実際に表していることをクライアントが確認できます。
サーバーは、自らが表すと唱える組織に属していることを証明するため、クライアントに公開キー証明書を提示します。 この証明書が有効であれば、クライアントはサーバーの識別情報について確信できます。
クライアントとサーバーは、同じ秘密キーについて同意できる情報を交換します。 たとえば、RSAを使う場合、クライアントは公開キー証明書で取得したサーバーの公開キーを使用して、秘密キー情報を暗号化します。 クライアントは暗号化された秘密キー情報をサーバーに送信します。 復号化にはサーバーの非公開キーが必要なので、サーバーでだけ、このメッセージを復号化できます。
クライアントとサーバーは、同じ秘密キーにアクセスします。 それぞれのメッセージでは、ハンドシェークの最初のステップで選択した暗号化ハッシュ関数と、共有された秘密情報を使用して、メッセージに添付されるHMACを計算します。 次に、秘密キーと、ハンドシェークの最初のステップでネゴシエーションされた秘密キー・アルゴリズムを使用し、セキュアなデータとHMACを暗号化します。 そのあと、クライアントとサーバーは、暗号化されハッシュ化されたデータを使ってセキュアに通信することができます。
TLS 1.2ハンドシェークでは、SSLハンドシェークについて概要を説明しました。これは、暗号化されたメッセージを送信する前にクライアントとサーバーの間で行われる情報の交換です。 詳細は、図「SSL/TLSハンドシェイク」を参照してください。 これは、SSLハンドシェークで交換される一連のメッセージを示しています。 特定の状況下でだけ送信されるメッセージには「optional」と記されています。 各SSLメッセージについては、後で詳しく説明します。
SSL/TLSハンドシェイク
SSLメッセージは、次の順序で送信されます。
ノート: クライアントに証明書を要求するのは、ごく一部のインターネット・サーバー・アプリケーションのみです。
close_notify
アラートを送信して、接続がクローズされたことをピアに通知します。SSLセッションで生成したパラメータを保存しておけば、将来のSSLセッションでこれらのパラメータを再利用できます。 SSLセッションのパラメータを保存しておけば、暗号化通信をすばやく開始できます。
初期のハンドシェークが完了してアプリケーション・データが流れているとき、いずれの側からでも新しいハンドシェークをいつでも開始できます。 特に重要な操作について、アプリケーションで強力な暗号化方式群を使用したり、サーバー・アプリケーションでクライアント認証が必要になる場合もあります。
理由は何であれ、新しいハンドシェークが既存の暗号化セッションに置き換わり、新しいセッションが確立されるまで、アプリケーション・データとハンドシェーク・メッセージが交互に配置されます。
アプリケーションで次のいずれかのメソッドを使用して、新しいハンドシェークを開始できます。
SSLSocket.startHandshake()
SSLEngine.beginHandshake()
SSL/TLSプロトコルは、protected
接続を確保するための特定の一連のステップを定義します。 ただし、暗号化方式群の選択が、接続で確保するセキュリティのタイプに直接影響します。 たとえば、匿名暗号化方式群を選択した場合、アプリケーションにはリモート・ピアの識別情報を検証する方法がありません。 暗号化しない方式群が選択された場合は、データの機密性を保護できません。 またSSL/TLSプロトコルでは、受信した資格と、ピアから送信されることが予期される資格が一致するようにとは規定していません。 接続がなんらかの理由で悪意のあるピアにリダイレクトされたときに、悪意のあるピアのクレデンシャルが現在のトラスト・データに基づいて受け付けられた場合、その接続は有効とみなされてしまいます。
raw SSLSocket
およびSSLEngine
クラスを使用する場合は、データの送信前に必ずピアのクレデンシャルをチェックしてください。 SSLSocket
およびSSLEngine
クラスは、URL内のホスト名がピアのクレデンシャル内のホスト名と一致することを自動的に検証しません。 ホスト名が検証されない場合、URL不正行為によってアプリケーションが悪用される可能性があります。 JDK 7以降、SSL/TLSハンドシェイク中にエンドポイントの識別/検証手順を処理できます。 SSLParameters.getEndpointIdentificationAlgorithm
メソッドを参照してください。
HTTPS (HTTP Over TLS)などのプロトコルでは、ホスト名検証が必要です。 JDK 7以降、HTTPSエンドポイントの識別は、デフォルトでHttpsURLConnection
のハンドシェーク中に適用されます。 SSLParameters.getEndpointIdentificationAlgorithm
メソッドを参照してください。 または、アプリケーションはHostnameVerifier
インタフェースを使用して、デフォルトのHTTPSホスト名ルールをオーバーライドできます。 「HostnameVerifierインタフェース」および「HttpsURLConnectionクラス」を参照してください。