#このページで確認できること
- TLS 1.2 / 1.3 のハンドシェイクの往復数と流れの違いをシーケンスで確認する
openssl s_clientで証明書チェーン・プロトコルバージョン・cipher を確認する- ClientHello の SNI・ALPN が、ECH の利用有無でどのように見えるかを確認する
- TLSインスペクション装置による証明書差し替えを Issuer の比較で確認する
- 観察する項目: 証明書チェーンの Issuer、
Protocol/Cipher、SNI、ALPN
実装上の制約: 本ラボのローカル nginx 例は平文HTTPのため、TLS の検証は自前の証明書を設定するか、HTTPS で提供されるホストに対して行ってください。TLS 1.0 / 1.1 は利用非推奨(RFC 8996)のため扱いません。
ECHは標準化されていますが、実際に利用されるのは、クライアントとサーバーが対応し、ECH設定が配布され、ハンドシェイクで受理された場合です。対応の有無だけで利用を断定せず、実際の接続を観測してください。
#ハンドシェイク — 1.2 と 1.3 の違い
TLS 1.3の初回ハンドシェイクは、HelloRetryRequestが必要ない代表的なケースで1往復で完了し、証明書を含むサーバー側パラメータの大半を暗号化します。証明書ベースのTLS 1.2フルハンドシェイクで送られるサーバー証明書は受動キャプチャで読めますが、TLS 1.3の証明書はキーログ等なしの受動キャプチャでは読めません。再開セッションやPSKなど、証明書自体を送らないハンドシェイクは別です。
participants: Client, Server Client -> Server: ClientHello (SNI, cipher suites) Server --> Client: ServerHello + Certificate (平文) Server --> Client: ServerKeyExchange + ServerHelloDone Client -> Server: ClientKeyExchange + ChangeCipherSpec + Finished Server --> Client: ChangeCipherSpec + Finished note: ここから暗号化されたアプリケーションデータ Client -> Server: Application Data (HTTP request)
participants: Client, Server Client -> Server: ClientHello (SNI, key_share, ALPN) Server --> Client: ServerHello (key_share) Server --> Client: EncryptedExtensions + Certificate + Finished (暗号化) Client -> Server: Finished note: この例は 1 RTT。再接続でPSKとサーバー許可等の条件を満たせば0-RTTも可能 Client -> Server: Application Data (HTTP request)
#平文で見える情報
| フィールド | TLS 1.2 | TLS 1.3 |
|---|---|---|
| SNI (server_name) | 平文 | ECH未使用時は平文。ECH利用時は実際のSNIをClientHelloInnerで暗号化 |
| ALPN (クライアント提示) | 平文 | ECH未使用時は平文。ECH利用時は実際の候補をClientHelloInnerで暗号化可能 |
| ALPN (サーバー選択) | 平文 | 暗号化 (EncryptedExtensions 内) |
| サーバー証明書 | 証明書ベースのフルハンドシェイクで送られる場合は平文 | 送られる場合は暗号化 |
| cipher suites 候補 | 平文 | ClientHelloOuterの候補は平文。ECH利用時のClientHelloInnerは暗号化 |
ECHを使わない接続ではSNIが平文のため、プロキシ・SWG・ファイアウォールが復号せずに宛先ホスト名でフィルタリングできる場合があります。ECHが受理された接続では実際のSNIとALPN候補が保護されるため、ClientHelloOuterに見える公開名だけで同じ判断はできません。またTLS 1.3のサーバー証明書は、キーログ等のない受動キャプチャからは確認できません。
#検証コマンド
openssl — 証明書チェーンとネゴシエーション結果$ openssl s_client -connect example.com:443 -servername example.com </dev/null # Certificate chain / Protocol / Cipher を確認する $ openssl s_client -connect example.com:443 -tls1_2 </dev/null 2>/dev/null | grep Protocol # バージョンを固定して、サーバーが受け付けるかを確認する $ openssl s_client -connect example.com:443 </dev/null 2>/dev/null \ | openssl x509 -noout -issuer -subject -dates # Issuer / Subject / 有効期限だけを取り出すcurl — バージョン指定と証明書情報
$ curl -v --tlsv1.3 --tls-max 1.3 https://example.com/ -o /dev/null 2>&1 | grep -E 'SSL connection|issuer:' $ curl -v --tls-max 1.2 https://example.com/ -o /dev/null 2>&1 | grep 'SSL connection'出力例 (証明書チェーンとcipherは時期・環境で変わる)
openssl s_client の Issuer を比較します。経由時に Issuer が社内CA(装置のCA)に変わっていれば、そのセッションは復号されています。あわせて Protocol / Cipher が装置側の設定値に固定されていないかも確認します。
#観測ポイント
| curl | -v の SSL connection using ... 行でバージョンと cipher、issuer: 行で発行者。最低バージョンを指定する --tlsv1.3 と、上限を指定する --tls-max 1.3 を併用するとTLS 1.3に固定できる。 |
|---|---|
| DevTools | Security タブでプロトコルバージョン・鍵交換・証明書チェーンを確認。鍵アイコン → 証明書で Issuer を確認。 |
| Proxy | 従来型の明示プロキシは CONNECT host:443 でTCPトンネルを張る。CONNECT 行(平文)とその後の TLS の区別をつけて観測する。SNI ベースの判定を検証するときは、ECHの利用有無も確認する。 |
| tcpdump / Wireshark | フィルタ: tls.handshake.type == 1 (ClientHello)、tls.handshake.extensions_server_name (SNI)。ECH利用時はClientHelloOuterと暗号化されたClientHelloInnerを区別する。暗号化部分の解析にはSSLKEYLOGFILE等の鍵情報が必要。 |
| TLS inspection | Issuerが社内CAに変わる、TLSバージョン・cipherが装置設定に制約される、証明書の有効期間が装置生成の値になる、といった差をdirect接続と比較する。クライアント証明書認証やピンニングを使うアプリは、装置の方式によって復号例外(bypass)が必要になる場合がある。 |
#関連
ALPN によるプロトコル選択は HTTP/2、TLS 1.3 をトランスポートに統合した設計は QUIC を参照。UDP 上で TLS 相当を実現する DTLS は別ページで扱います。