Old-School Networking / 2026 ・ No.08

いにしえのネットワーク入門

第8回 第5・6層と TLS ── 申請に鍵をかける

公開

Wireshark の画面。一覧には TCP のあいさつ、4番の Client Hello (SNI=expenses.example)、Server Hello、Application Data が並び、最後に FIN と RST がある。4番が選ばれ、明細の Transport Layer Security が開かれて、Extension: server_name の中の Server Name: expenses.example が選ばれている。バイトの欄では expenses.example の文字が青くなっている
HTTPS で申請を送ったときの記録。4番の Client Hello を開くと、つなぎたい相手の名前(SNI)expenses.example だけは、暗号の前なので読めます(筆者がクラウド上に作った練習用ネットワークで、2026年10月25日に記録したものを Wireshark 4.2.2 で開いて撮影。画面は英語のまま。ウインドウの上の帯と見出しは説明のために描き足したもの)

ここまでの申請は、途中の誰にでも中身が読める状態で運ばれていました。今回は、TCP とアプリの間に入って申請に鍵をかける TLS です。HTTPS の S の正体でもあります。
練習用の CA(証明書を発行する役)を作ってサーバーに証明書を渡し、HTTPS にすると何が見えなくなり、何がまだ見えていて、どれだけ遅くなるのか。確かめに失敗する4つの場面も、わざと作って確かめます。

一

表し方と会話の層

新井路線図の 8 番、「第5・6層」ってまとめてありますね。どうして1つの回なんですか?

古井インターネットの実際では、第5層と第6層はほとんど独立していない。TLS やアプリの中に溶けこんでいるんだ。だから一緒に片づける。

全12回の路線図(いまここ:第8回)

1 全体図 2 物理層 3 データリンク層 4 IP アドレス 5 ルーター 6 TCP 7 UDP・ソケット 8 TLS 9 DNS 10 HTTP 11 開発者の網 12 切り分け いまここ 全体図 第1層 第2層 第3層 第4層 第5・6層 第7層 実践
  • 第5・6層 ── 表し方(文字コード、JSON、圧縮、暗号)と会話の管理
  • HTTPS にする ── 何が見えなくなるか、どれだけ遅くなるか(実測)
  • 鍵と証明書 ── 鍵の共有、証明書の連なり、確かめに失敗する4つの場面(実測)
  • まだ見えるもの ── 名前(SNI)と、それを隠す ECH。証明書の期限が短くなる流れ

第5・6層は、アプリと TCP の間にいる

7 第7層 アプリ HTTP、申請の API 6 第6層 表し方 UTF-8、JSON、gzip、暗号 5 第5層 会話の管理 始まり・終わり・再開 4 第4層 トランスポート TCP、UDP TLS 2つにまたがる インターネットの実際では、第5・6層は独立した層ではなく、 TLS やアプリ、ライブラリの中に溶けこんでいる

第6層は表し方の層です。同じ「交通費」でも、相手と同じ決まりで並べなければ読めません。いまの決まりは、文字なら UTF-8、データなら JSON、縮めるなら gzip です。

# 「交通費」は UTF-8 で 9 バイト(第7回の表紙のバイトの欄にも出ていた)
    交通費 → e4 ba a4 e9 80 9a e8 b2 bb
# CSV 2 MB を gzip で縮める(同じ行のくり返しなので極端に縮む)
    2,097,152 bytes → 6,179 bytes

第5層は会話の管理の層で、会話の始まりと終わり、途切れたときの再開を受け持ちます。TCP の接続や、HTTP のクッキー、TLS の再開の機能などに分かれて入っています。そして暗号も表し方の一つ。TLS は、この2つの層にまたがる仕事をしています。

二

丸見えの申請

第7回の結びで、申請の JSON が Wireshark でそのまま読めることに気づきました。記録ファイルの中から、申請の文字を探してみます。

# 記録ファイルの中から、申請の文字を探す
    HTTP   '"amount":1280'       見つかった
    HTTP   'POST /api/expenses'  見つかった
    HTTPS  '"amount":1280'       見つからない
    HTTPS  'POST /api/expenses'  見つからない
    HTTPS  'expenses.example'    見つかった  ← Client Hello SNI
Wireshark の明細とバイトの欄を2つ縦に並べたもの。上は HTTP の申請で、バイトの欄の右側に POST /api/expenses、Host、Content-Type、そして JSON の date と amount 1280 の文字が読める。下は HTTPS の申請で、Transport Layer Security とだけ表示され、バイトの欄の右側は意味のない記号の並び
同じ申請を、HTTP と HTTPS で送ったときの比べ。HTTPS では、URL も JSON も、途中からは読めません(筆者がクラウド上に作った練習用ネットワークで、2026年10月25日に記録したものを Wireshark 4.2.2 で開いて撮影。画面は英語のまま。ウインドウの上の帯と見出しは説明のために描き足したもの)

HTTP の記録には、URL も金額もそのまま入っています。途中のルーターや、同じ Wi-Fi にいる誰か、プロバイダの機械を通るたびに、読める状態で運ばれていたわけです。読めるということは、書きかえて先へ渡すこともできるということです。HTTPS の記録からは、URL も金額も見つかりませんでした。ただ一つ、expenses.example という名前を除いて(第7章)。

TLS の3つの約束

読まれない 暗号化 途中の誰にも 中身は意味のないバイト 書きかえに気づく 改ざんの検知 1ビットでも変われば 受け取りを拒む 相手が本物 証明書 名前・期限・署名を 確かめてから話す 3つそろって初めて安全。暗号化しても、相手が偽物なら意味がない TLS が守るのは線の上だけ。両端の PC やサーバーの中は守らない
三

HTTPS にする

サーバーに、名前 expenses.example の証明書を持たせ、Node.js の https で 3443 番に申請の API を立てました(.example は説明用に予約された名前です)。証明書は、筆者が作った練習用の CA「Kiji Practice Root CA」で発行しました。PC の curl には、その CA を --cacert で教えています。

つながるまでTLS のあいさつ完了返事の最初の1バイト往復の数
HTTP0.041 秒—0.083 秒2
HTTPS(TLS 1.3)0.041 秒0.085 秒0.127 秒3
HTTPS(TLS 1.2)0.041 秒0.126 秒0.168 秒4

往復 0.041 秒の線で、HTTP は返事まで 2 往復。HTTPS(TLS 1.3)は TLS のあいさつで 1 往復増えて 3 往復、古い TLS 1.2 では 2 往復増えて 4 往復でした。暗号の計算そのものにかかった時間は、ほんの数ミリ秒です。遅さの正体は、計算ではなく往復なのです。

# TLS 1.3(片道 20 ms の線):TCP のあいさつのあと、TLS のあいさつは 1 往復。申請(9番)は暗号の中
   1  0.000  pc  → srv  TCP      [SYN]
   2  0.041  srv → pc   TCP      [SYN, ACK]
   3  0.041  pc  → srv  TCP      [ACK]
   4  0.043  pc  → srv  TLSv1    Client Hello (SNI=expenses.example)
   5  0.083  srv → pc   TCP      [ACK]
   6  0.084  srv → pc   TLSv1.3  Server Hello, Change Cipher Spec, Application Data, Application Data, Application Data, Application Data
   7  0.084  pc  → srv  TCP      [ACK]
   8  0.085  pc  → srv  TLSv1.3  Change Cipher Spec, Application Data
   9  0.086  pc  → srv  TLSv1.3  Application Data
  10  0.126  srv → pc   TLSv1.3  Application Data, Application Data
  11  0.130  srv → pc   TLSv1.3  Application Data
# TLS 1.2:TLS のあいさつに 2 往復。申請(10番)はそのあと
   1  0.000  pc  → srv  TCP      [SYN]
   2  0.041  srv → pc   TCP      [SYN, ACK]
   3  0.041  pc  → srv  TCP      [ACK]
   4  0.042  pc  → srv  TLSv1    Client Hello (SNI=expenses.example)
   5  0.083  srv → pc   TCP      [ACK]
   6  0.083  srv → pc   TLSv1.2  Server Hello, Certificate, Server Key Exchange, Server Hello Done
   7  0.083  pc  → srv  TCP      [ACK]
   8  0.085  pc  → srv  TLSv1.2  Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
   9  0.128  srv → pc   TLSv1.2  Change Cipher Spec, Encrypted Handshake Message
  10  0.128  pc  → srv  TLSv1.2  Application Data
  11  0.170  srv → pc   TLSv1.2  Application Data

TLS 1.3 のあいさつ(実測の時刻)

PC サーバー SYN 0 SYN+ACK ACK, Client Hello 43 ms Server Hello … Finished, POST 86 ms 201 TCP のあいさつ 1 往復 TLS のあいさつ 1 往復(1.2 は 2 往復) 申請と返事 1 往復 Server Hello より後ろは、もう暗号の中(証明書も)
Wireshark のパケット一覧を2つ縦に並べたもの。上は TLS 1.2 で、Client Hello、Server Hello, Certificate, Server Key Exchange, Server Hello Done、Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message、Change Cipher Spec, Encrypted Handshake Message のあと、10番の 0.128 秒に Application Data。下は TLS 1.3 で、Client Hello、Server Hello, Change Cipher Spec, Application Data のあと、9番の 0.086 秒に Application Data
TLS 1.2 と 1.3 のあいさつの比べ。1.3 ではあいさつが1往復減り、申請を送り始めるのが 0.042 秒早くなりました(筆者がクラウド上に作った練習用ネットワークで、2026年10月25日に記録したものを Wireshark 4.2.2 で開いて撮影。画面は英語のまま。ウインドウの上の帯と見出しは説明のために描き足したもの)

TLS 1.3 では、PC が最初の Client Hello で鍵の材料を先に送ってしまうので、サーバーの返事(Server Hello)を受け取った時点で暗号の準備ができます。証明書も、Server Hello より後ろはもう暗号の中です。TLS 1.2 では、材料のやりとりにもう1往復かかっていました。TLS 1.0 と 1.1 は、2021 年に正式に使用をやめるよう定められています。

POINT

往復が増える分、第6回の「接続の使い回し」がいっそう効きます。HTTPS では、つなぎ直すたびに TCP と TLS で2往復。keep-alive や接続プールは必須です(第10回)。

四

鍵をどう決めるか

新井暗号の鍵って、どうやって相手に渡すんですか? 線で送ったら、それこそ途中で読まれますよね。

古井鍵そのものは送らない。それぞれが手元で同じ鍵を計算するんだ。

鍵は送らず、両側で同じものを計算する

PC 秘密 a 線に出さない 公開してよい A 同じ鍵 サーバー 秘密 b 線に出さない 公開してよい B 同じ鍵 Client Hello と Server Hello で交換 途中で見えるのは A と B だけ そこから鍵は計算できない a + B b + A 両側で同じ鍵ができる この回の実測では X25519。接続ごとに作り直すので、あとで秘密が漏れても過去の記録は読めない

PC とサーバーは、それぞれ秘密の数を作り、そこから計算した「公開してよい数」だけを Client Hello と Server Hello に載せて交換します。自分の秘密と相手の公開の数を組み合わせると、両側で同じ鍵ができます。途中で公開の数を見ても、鍵は計算できません。秘密は接続ごとに作り直して捨てるので、あとでサーバーの鍵が漏れても、過去の記録を読み解くことはできません(前方秘匿性)。

# openssl s_client で、決まった中身を見る
pc$ openssl s_client -connect 203.0.113.20:3443 -servername expenses.example -CAfile ca.pem -brief
    Protocol version: TLSv1.3
    Ciphersuite: TLS_AES_256_GCM_SHA384
    Peer certificate: CN = expenses.example
    Hash used: SHA256
    Signature type: ECDSA
    Verification: OK
    Server Temp Key: X25519, 253 bits
# 証明書の連なり(0 がサーバー、i: は署名した者)
    0 s:CN = expenses.example
    i:CN = Kiji Practice Root CA
    Verify return code: 0 (ok)
# サーバーの証明書
    subject=CN = expenses.example
    issuer=CN = Kiji Practice Root CA
    notBefore=Oct 24 23:40:01 2026 GMT
    notAfter=Jan 22 23:40:01 2027 GMT
    DNS:expenses.example

openssl s_client で見ると、この接続は TLS 1.3、鍵の共有は X25519、中身の暗号は TLS_AES_256_GCM_SHA384 でした。AES-256-GCM は、暗号にすると同時に「書きかえられていないか」の印も付けるので、3つの約束のうち2つをこれで果たします。残る1つ、相手が本物かどうかを受け持つのが、証明書です。

五

相手が本物か:証明書

鍵の共有がどれほど安全でも、相手が偽物のサーバーなら、偽物と安全に話すだけです。そこでサーバーは、証明書を見せて「わたしは expenses.example です」と名乗ります。証明書には、名前、期限、公開鍵が書かれ、信頼できる CA の署名が付いています。

署名をたどって、信頼できるルートに着くか

ルート CA OS・ブラウザが最初から信頼 中間 CA (この回の練習では省略) 署名 サーバーの証明書 expenses.example 署名 信頼する CA の一覧 OS・ブラウザに入っている PC が確かめること ✓ 名前が合うか(expenses.example) ✓ 期限の内か(2027-01-22 まで) ✓ 署名をたどってルートに着くか 練習用 CA は筆者の PC の一覧には入っていないので、curl に --cacert で教えた 本物のサイトは、Let's Encrypt などの CA から証明書をもらう

本物のサイトの証明書は、OS やブラウザに最初から入っている「ルート CA」から、中間 CA を経て署名されています。PC は、名前が合うか・期限の内か・署名をたどってルートに着くかの3つを確かめます。この回の練習用 CA は筆者の PC の一覧に入っていないので、curl に教えて信頼させました。

六

確かめに失敗する4つの場面

開発中に一度は見るエラーを、わざと起こしました。名前違い、期限切れ、自己署名の証明書は、それぞれ練習用に作ったものです。

# 練習用 CA を教えずにつなぐ
    curl: (60) SSL certificate problem: unable to get local issuer certificate
# 住所(IP)でつなぐ。証明書の名前は expenses.example
    curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.20'
# 期限切れの証明書(2026-09-29 まで)
    curl: (60) SSL certificate problem: certificate has expired
# 自分で自分に署名した証明書
    curl: (60) SSL certificate problem: self-signed certificate
# 練習用 CA を教え、名前でつなぐ → 確かめに成功
    HTTP 404 (GET /api/expenses)
エラーどの確かめに失敗したか正しい直し方
unable to get local issuer certificate署名をたどってもルートに着かない中間証明書もサーバーに設定する。社内 CA なら、その CA を信頼する一覧に入れる
no alternative certificate subject name matches名前が合わない証明書に書かれた名前でつなぐ。必要な名前を証明書に入れる
certificate has expired期限切れ更新する。自動更新にする(第8章)
self-signed certificate信頼できる署名がないCA から発行してもらう。開発用なら手元に開発用の CA を作る
POINT

エラーを消すために、確かめそのものを切ってはいけません(curl の -k、Node.js の NODE_TLS_REJECT_UNAUTHORIZED=0、Python requests の verify=False など)。暗号はかかっても、相手が本物かどうかがわからなくなり、3つの約束の1つが消えます。開発中に「とりあえず」で入れたものが本番に残る事故は、昔から絶えません。

七

まだ見えているもの

表紙の写真のとおり、Client Hello の SNI には、つなぎたい相手の名前 expenses.example がそのまま書かれています。1台のサーバーがたくさんの名前のサイトを抱えているとき、どの証明書を出せばよいかを、暗号の前に知る必要があるからです。ほかにも、相手の IP アドレス、通信の量と時刻は、TLS をかけても途中から見えます。

この名前を隠すために、Client Hello そのものを暗号にする ECH(Encrypted Client Hello)が、2026 年 3 月に RFC 9849 として標準になりました。ただし、名前は DNS の問い合わせ(第9回)からも漏れるので、両方がそろって初めて隠れます。

八

証明書の期限と自動更新

公開サイトの証明書の最長の期限(CA/Browser Forum の決定)

〜2026-03-14 398 日 2026-03-15 から 200 日 2027-03-15 から 100 日 2029-03-15 から 47 日 期限が短いほど、盗まれた鍵や間違った証明書の害が短くて済む 人の手で更新するのは無理になり、自動更新(ACME)が前提になる

ブラウザと CA の業界団体 CA/Browser Forum は、公開サイトの証明書の期限を段階的に短くすることを決めました。2026 年 3 月 15 日からは最長 200 日、2029 年 3 月 15 日からは 47 日です。年に数回の更新を人の手でこなすのは現実的ではないので、ACME という手順で自動的に発行・更新するのが前提になります。無料の CA の Let's Encrypt も、この ACME で証明書を配っています。

開発者としては、「証明書の期限切れで止まる」事故を、監視と自動更新で防ぐことが大切です。期限は openssl x509 -noout -dates や、ブラウザの鍵のマークから確かめられます。

九

自分の PC で確かめる

調べたいことどうやって
TLS の版と暗号openssl s_client -connect example.com:443 -servername example.com -brief
あいさつの経過と証明書curl -v https://example.com/ -o /dev/null
あいさつにかかった時間curl -o /dev/null -s -w '%{time_connect} %{time_appconnect}\n' URL
証明書の期限openssl x509 -in cert.pem -noout -dates
信頼する CA の一覧Mac:キーチェーンアクセス、Windows:certmgr.msc、Linux:/etc/ssl/certs

ブラウザのアドレス欄の左の印を押すと、そのサイトの証明書を見られます。発行した CA、名前、期限を確かめてみましょう。

結 — 一枚まとめと、次回

  1. 第6層は表し方(UTF-8、JSON、gzip、暗号)、第5層は会話の管理。実際には TLS やアプリに溶けこんでいる。
  2. HTTP の記録では URL も金額も読めた。HTTPS では見つからない。
  3. TLS の約束は3つ:読まれない・書きかえに気づく・相手が本物。
  4. HTTPS(TLS 1.3)は HTTP より 1 往復、TLS 1.2 は 2 往復多い。遅さの正体は計算ではなく往復。
  5. 鍵は送らず、公開してよい数を交換して両側で計算する(X25519)。接続ごとに作り直す。
  6. 証明書は名前・期限・署名の連なりを確かめる。失敗しても、確かめを切ってはいけない。
  7. SNI の名前、IP、量と時刻は見えている。名前は ECH(RFC 9849)で隠せる。証明書の期限は 2029 年に 47 日へ。

新井そういえば、curl にずっと --resolve で「expenses.example は 203.0.113.20」って書いてましたよね。あれ、ずるくないですか?

古井ずるい。本当は、名前から住所を引く仕組みがある。次回は DNS。インターネットの電話帳だ。

参考

記録は、筆者がクラウド上の Linux(Ubuntu 24.04、カーネル 6.18)にネットワーク名前空間で作った練習用ネットワークで、2026年10月25日に取ったものです。PC とサーバーの間は第6回のいたずら線(片道 20 ミリ秒)です。証明書は、筆者が OpenSSL 3.0.13 で作った練習用の CA から発行し(期限切れのものは Python の cryptography で日付を指定して作成)、サーバーは Node.js 22(OpenSSL 3.5)、クライアントは curl 8.5.0 です。表の数字はすべて、この記録とそのときのコマンドの出力から読んだ実際の値です。証明書の期限の決まりは CA/Browser Forum の決定(SC-081)を伝える DigiCert と DNSimple の告知によります。登場人物は架空の人物です。

いにしえのネットワーク入門 第8回 — 第5・6層と TLS / 2026.10

← 記事一覧へ