ブラウザ通信の流れ
1. 通信の大きな流れ
- TCP 接続(3 ウェイハンドシェイク)
- SYN → SYN/ACK → ACK でコネクション作成
- HTTP でも HTTPS でも実行、SSL/TLS 以前の土台
- TLS ハンドシェイク
- 暗号化の準備をする段階
- サーバーの証明書を検証し、暗号化に使う鍵を決める
- 暗号化された通信の開始
- HTTP リクエストを暗号化して送る
証明書の検証に失敗すると 2. で止まり、HTTP リクエストはサーバーに届きません。
2. 用語の整理
| 用語 | 意味 |
|---|---|
| 認証局(CA) | 証明書を発行(署名)する組織・役割 |
| サーバー証明書 | サーバーの公開鍵・ドメイン名・有効期限・認証局名・認証局の署名 |
| 中間証明書 | 中間認証局の公開鍵・上位の認証局の署名 |
| ルート証明書 | 一番上の認証局の証明書。自分自身で署名している(自己署名) |
| CA 一覧(CA バンドル) | クライアントが最初から持っている、信頼するルート証明書のリスト |
- 「認証局」は組織、「〇〇証明書」はその認証局の身分証
- 証明書は単なる公開鍵ではなく、「この公開鍵は誰のものか」に認証局の署名でお墨付きを与えたもの
3. サーバーが送ってくるもの
サーバーはハンドシェイクで、証明書の連鎖をまとめて送ってくる。
[0] example.com ← サーバー証明書(中間 CA-1 が署名)
[1] 中間 CA-1 ← 中間証明書(中間 CA-2 が署名)
[2] 中間 CA-2 ← 中間証明書(ルート CA が署名)
(ルート CA) ← 送られてこない。クライアントの CA 一覧にある
- 送る: サーバー証明書と中間証明書
- クライアントは中間証明書を普通持っていないので、サーバーが送る必要がある
- 送らない: ルート証明書
- 送られてきても信頼の根拠にはならない
4. クライアントの検証手順
- サーバー証明書の署名を、中間証明書の公開鍵で確かめる
- 中間証明書の署名を、その上の証明書の公開鍵で確かめる(繰り返し)
- 連鎖の最後の証明書に書かれた発行者名で、CA 一覧からルート証明書を探す
- 見つかったルート証明書の公開鍵で、最後の証明書の署名を確かめる
- すべて正しければ検証成功
ルート証明書は「検証しない」
- ルート証明書は自己署名なので、署名を確かめても正しさは証明できない
- 「CA 一覧に入っているルートは信頼する」と最初から決めている(トラストアンカー)
- 信頼の根拠は、サーバーから送られてきたものではなく、手元の CA 一覧
CA 一覧は誰が管理しているか
- ブラウザや OS のベンダーが審査して管理している(Mozilla / Apple / Microsoft / Google など)
- アップデートで追加や削除がある
- アプリやライブラリが独自の CA 一覧ファイル(例:
cacert.pem)を持っていることもある
5. クロス署名
新しいルート認証局は、まだ多くの CA 一覧に入っていない。 そこで、すでに広く信頼されている古いルートに署名してもらった証明書も用意する。
[2] 新ルート CA(クロス署名版)← 発行者: 旧ルート CA
旧ルート CA ← CA 一覧にある
- CA 一覧に新ルートがある環境では、新ルートで検証が終わる
- 旧ルートしかない環境では、旧ルートの公開鍵で新ルートの証明書を確かめて終わる
- 名前に「Root」と付いていても、その連鎖での終点(真のルート)は、クライアントの CA 一覧によって変わる
6. よくあるエラー: unable to get local issuer certificate
意味は「発行者の証明書が手元にない」で、連鎖をたどりきれないときに出る。
| 原因 | 状況 |
|---|---|
| クライアントの CA 一覧が古い | 新しいルートが一覧に入っていない |
| サーバーが中間証明書を送っていない | サーバーの設定ミス。ブラウザは中間証明書を自動で補うことがあるため、ブラウザでは見られるのに curl などでは失敗する |
7. 実運用での注意点
- ライブラリ独自の CA 一覧に注意
- OS の CA 一覧を使わず、同梱の古い CA ファイルを使うライブラリがある
- コードで CA ファイルを指定すると(curl の
CURLOPT_CAINFOなど)、php.ini などの設定より優先される - メンテナンスが止まったライブラリでは、CA 一覧が古いまま残る
- コンテナの CA 一覧はイメージの中のもの
- ECS / Fargate などのホスト側の CA 一覧は使われない
- CA 一覧はイメージをビルドした時点のもので固定されるので、更新にはイメージの作り直しが必要
- 確認コマンド
```bash
サーバーが送ってくる証明書の連鎖を見る
echo | openssl s_client -connect example.com:443 -servername example.com
特定の CA ファイルで検証できるか試す
curl –c