TLSの基礎
HTTPSの土台となるTLSが何を保証し、ハンドシェイクでどう通信を確立するかを理解する
TL;DR
- TLSは通信の 暗号化・認証・改ざん検知 の3つを提供するプロトコル
- ハンドシェイクで証明書の検証と共通鍵の交換を行い、その後の通信を共通鍵で暗号化する
- TLS 1.3はラウンドトリップが1回に削減され、古い暗号スイートが排除されたモダンな仕様
TLS とは
TLS(Transport Layer Security)は「トランスポート層のセキュリティ」という意味で、名前の通りネットワークのトランスポート層(TCP上)で動作し、その上を流れる通信を保護するプロトコル。
前身は Netscape が1990年代に開発した SSL(Secure Sockets Layer)。SSL 3.0 に深刻な脆弱性(POODLE攻撃など)が見つかったため、IETF(Internet Engineering Task Force)が標準化し名称を TLS に改めた。IETFはインターネット技術の標準化を担う国際的な組織。現在 SSL は廃止されており、「SSL証明書」「SSLサーバー」という言葉はいまも慣用的に使われるが、実態はすべてTLS。
| 名称 | バージョン | 状態 |
|---|---|---|
| SSL 2.0 / 3.0 | 1990年代 | 廃止(深刻な脆弱性) |
| TLS 1.0 / 1.1 | 1999 / 2006 | 廃止(RFC 8996) |
| TLS 1.2 | 2008 | 現役だが移行推奨 |
| TLS 1.3 | 2018 | 現在の標準 |
TLSが提供する3つの保証
| 保証 | 内容 |
|---|---|
| 機密性(Confidentiality) | 通信内容を第三者に読まれない(暗号化) |
| 完全性(Integrity) | 通信内容が途中で改ざんされていない(MAC(Message Authentication Code)による検証)。MACはメッセージが改ざんされていないことを検証するための認証コード |
| 認証(Authentication) | 接続先が本当に意図したサーバーである(証明書による検証) |
HTTPSは「HTTP over TLS」。TLSなしのHTTPはこれらを一切保証しない。
証明書とは何か
CA(Certificate Authority、認証局)とは、証明書の発行・署名を行う第三者機関のこと。Let's Encrypt・DigiCert・GlobalSign などが代表例。ブラウザや OS はあらかじめ信頼する CA の一覧を持っており、その CA が署名した証明書だけを正当なものとして扱う。
TLSで使われる証明書(X.509証明書)は、「この公開鍵はこのドメインのものである」をCAが保証した文書。
証明書に含まれる主な情報:
- Subject(CN / SAN にドメイン名や IP が入る)
- 公開鍵
- 有効期限
- 発行者(CA)の情報
- CAの署名クライアントは証明書を受け取ったとき、次を確認する。
- CAの署名が正しいか(信頼できるCAが署名しているか)
- 有効期限が切れていないか
- 証明書のSAN(Subject Alternative Name)が接続先ドメインと一致しているか。SANは証明書内でその証明書が有効なドメイン名・IPアドレスを列挙するフィールド
証明書の作り方・CSRの用途指定については mTLS・RSA・CSRの基礎 を参照。
TLSハンドシェイクの流れ(TLS 1.3)
TLS 1.3では 1-RTT(1回のラウンドトリップ)で接続が確立する。
sequenceDiagram
participant C as Client
participant S as Server
C->>S: ClientHello(暗号スイート・鍵共有パラメータ)
S->>C: ServerHello(暗号スイート・鍵共有パラメータ)
Note over C,S: 共通鍵を導出(ECDHE)
S-->>C: Certificate(サーバー証明書)
S-->>C: CertificateVerify(秘密鍵による署名)
S-->>C: Finished
C-->>S: Finished
Note over C,S: ハンドシェイク完了(1-RTT)
C->>S: Application Data(暗号化)
点線矢印(-->>)は暗号化済みメッセージを表す。TLS 1.3では証明書も暗号化されて送られる。
TLS 1.2との主な違い
| 項目 | TLS 1.2 | TLS 1.3 |
|---|---|---|
| ハンドシェイク | 2-RTT | 1-RTT(0-RTTも可能) |
| 鍵交換 | RSA鍵交換も可(前方秘匿性なし) | ECDHE のみ(前方秘匿性を強制) |
| 廃止された暗号スイート | MD5, SHA-1, RC4, 3DES など | 自動的に排除 |
| 証明書の暗号化 | なし(平文で送信) | あり |
共通鍵はどうやって共有するか(鍵交換)
ハンドシェイクで最終的に双方が同じ共通鍵を持つ必要があるが、その鍵を直接ネットワークで送ると盗まれる。
TLS 1.3では ECDHE(Elliptic Curve Diffie-Hellman Ephemeral、楕円曲線ディフィー・ヘルマン鍵交換)を使う。楕円曲線暗号を利用して、鍵そのものを通信路に流すことなく双方が同じ共通鍵を導出できる仕組み。
双方が鍵ペアを生成し、互いの公開鍵を交換する。
→ それぞれの秘密鍵と相手の公開鍵から、同じ値(マスターシークレット)が計算できる。
→ マスターシークレットを元に共通鍵を導出する。秘密鍵は通信に流れないため、通信を傍受されても共通鍵を導出できない(前方秘匿性)。
証明書チェーン(信頼の連鎖)
ブラウザや OSがあらかじめ信頼しているのは ルートCA だけ。
実際のサーバー証明書は、中間CA(Intermediate CA)を経由して発行されることが多い。
ルートCA(OSが信頼)
└── 中間CA(ルートCAが署名)
└── サーバー証明書(中間CAが署名)クライアントはサーバーから送られた証明書チェーンをたどり、最終的にルートCAに到達できれば信頼できると判断する。
SNI(Server Name Indication)
1つのIPアドレスに複数のドメインを持つサーバーでは、TLSハンドシェイクの時点でクライアントが接続先ドメインを通知する必要がある。これが SNI(Server Name Indication)で、TLSの拡張機能として定義されている。
ClientHello に server_name 拡張を含める
→ サーバーは対応するドメインの証明書を選んで返すSNIがないと、サーバーはどのドメイン向けの証明書を返せばよいか判断できない。
よくある落とし穴
証明書にSANがなく接続が失敗する
古い証明書にはSANがなくCNだけのものがある。モダンなブラウザはCNを無視しSANで検証するため接続が拒否される。
中間CA証明書をサーバーに設定し忘れる
サーバー証明書だけ設定しても、クライアントが中間CAを知らないと検証に失敗することがある。証明書チェーンをまとめたフルチェーン(fullchain.pem)を設定する。
TLS 1.2以下だけ対応した古いクライアントとの接続
セキュリティ要件によりTLS 1.3のみを許可する設定にすると、古いクライアントが接続できなくなる。互換性が必要な場合はTLS 1.2も許可しつつ、弱い暗号スイートを無効化する。
証明書の有効期限切れ
Let's Encryptは90日で期限が切れる。自動更新(certbot renew等)の仕組みを必ず用意する。