- インターネット通信は、複数の階層がパケットを分担して処理する構造であり、階層化されたプロトコルのおかげで、開発者は転送・ルーティング・セキュリティの細かな実装を直接扱わなくてよい
- HTTPリクエストは、ブラウザによるメッセージ生成から始まり、DNS参照、TCP 3-way handshake、ルーター経由、サーバー応答へと続く段階的な流れに従う
- 基本的なHTTPではヘッダーと本文が平文でやり取りされるため、盗聴やサーバーなりすましに弱く、この限界を補うためにセキュリティ層が追加される
- HTTPSはHTTPにTLSの暗号化と検証を加えた形であり、TLS handshakeはバージョン・cipher suite・証明書・鍵交換情報をすり合わせて対称セッションキーを作る過程である
- TLS 1.3はRSAや脆弱なcipher suite・パラメータを除外して選択肢を絞ることで、従来方式よりよりシンプルで高速かつ安全なhandshakeを構成する
インターネット通信を見る階層モデル
- インターネットは相互接続されたコンピュータネットワークのネットワークであり、「Internet」は文字通り「ネットワークの間」を意味する
- パケット交換方式のメッシュネットワークとして動作し、パケットの配送可否や到着時間は保証されないbest-effort deliveryの構造である
- 再試行、順序保証、重複除去、セキュリティといった処理を複数の抽象化層が裏側で担うため、インターネットが滑らかに動作しているように見える
- 各階層は特定の機能を提供し、異なるプロトコルがその機能を実装できる
- このモジュール化のおかげで、ある階層のプロトコルを変更しても他の階層のプロトコルに影響を与えずに済むことがある
ネットワーク階層ごとの役割
- Application layerはアプリケーションごとのロジックを処理し、通信単位はメッセージで、HTTPが代表例である
- Security layerは暗号化と認証を提供し、通信単位はrecordで、TLSがその例である
- Transport layerは信頼性のあるデータ転送を担い、TCP segmentまたはUDP datagramを使用し、ポート番号で識別する
- Network layerはインターネットをまたいでパケットをルーティングし、識別子としてIPアドレスを使う
- Link layerは物理媒体に近い通信を管理し、frameを使用し、MACアドレスで識別する
- Physical layerはビットをデバイス間で物理的に転送し、光ファイバーやEthernet cableが例である
HTTPリクエストの流れ
パケットがサーバーに届く仕組み
- クライアントがリクエストを送ると、データパケットはサーバーへ直接移動するのではなく、複数のネットワーク機器やルーターを経由して、サーバーネットワークのゲートウェイへ到達する経路を探す
- その後、Link layerがローカル区間の転送を担当する
-
テキストがインターネットを渡る段階
- クライアントデバイスはHTTPリクエストデータをTCP segmentにカプセル化し、さらにIP packetで包む
- 有線接続であれば、Ethernet frameのようなLink layer frameでさらにカプセル化される
- frameはローカルネットワークを通じてクライアントのルーターへ送られる
- ローカルルーターはframeを受け取り、Link layer headerを取り除いたうえでIP packetを処理する
- ルーターは宛先IPアドレスを見て次のhopを決定する
- パケットは1台以上の中間ルーターを経由して次のネットワークへ転送され、各ルーターは次のhopを決めて送る処理を繰り返す
- パケットは最終的に宛先サーバーと同じネットワーク上のルーターに到達する
- このルーターは最終的なルーティング判断を行い、サーバーに対応するローカルデバイスへパケットを送る
- サーバー側のルーターはローカルネットワークsegmentを通じてパケットをサーバーへ転送する
- Link layerはframeがサーバーのネットワークインターフェースに正しく届くようにする
- サーバーはframeを受け取り、IP packetを取り出した後、カプセル化されたTCP segmentを処理して元のHTTPリクエストを再構成する
- インターネットをまたいでパケットを送るNetwork layerの過程は、ドメイン名解決やTCP handshakeのような前段階でも使われる
サーバー応答とブラウザのレンダリング
- サーバーはHTTPリクエストを処理した後、クライアントへHTTPレスポンスを送る
- レスポンスには、使用中のHTTPバージョン、
200・404 のようなステータスコード、レスポンスヘッダー、要求されたページのHTMLやJSONデータのような本文が含まれる
HTTP/1.1 200 OK
Date: Sat, 26 May 2023 10:00:00 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html
Content-Length: 3456
Example Page
Hello, world!
- クライアントはHTTPレスポンスを受け取り、処理する
- ブラウザはHTMLを解釈して画面にコンテンツをレンダリングする
- レスポンスに画像、CSS、JavaScriptのような追加リソースがあれば、ブラウザは同じ過程に従って追加のHTTPリクエストを送る
HTTPのセキュリティ問題とHTTPS
- 基本的なHTTPにはセキュリティがまったくない
- 通信を盗み聞きする者は、やり取りされるデータを100%見ることができる
- 誰かがサーバーになりすませば、クライアントが重要な情報を誤った相手に送ってしまう可能性がある
- HTTPSはHTTPに暗号化と検証を加えた形である
- HTTP通信を安全にする方法はいくつかあるが、現在一般的に使われている実装はTLSである
- TLSはクライアントとサーバーが互いの身元を検証し、双方だけが復号できる形でpayloadを暗号化できるようにする
- HTTPSリクエストの流れは先に見たHTTPリクエストの流れと同じだが、Application layerとTransport layerの間にSecurity layerが追加される
- TLS handshakeには通常TCPが使われる
TLS handshakeで合意すること
- TLS handshakeは、クライアントとサーバーが通信に使う複数の要素について合意する過程である
- 合意対象には、メッセージ検証、圧縮、暗号化に使うアルゴリズム群が含まれる
- このアルゴリズム群はcipher suiteと呼ばれる
- 厳密にはcompression algorithmを除いた残りがcipher suiteだが、この記事では全体の集合をcipher suiteと呼ぶ
- 例となる構成要素は次のとおり
- Compression algorithm: wire上のデータを圧縮する方式で、GzipやBrotliが例であり、現在は主にBrotliが使われる
- Key exchange algorithm: 公開チャネル上で暗号鍵を安全に交換する方式で、ECDHE-RSAやECDHE-ECDSAが例であり、現在は主にECDHEが使われる
- Authentication algorithm: handshake中に当事者の身元を認証する方式で、RSAやECDSAが例であり、RSAが広く使われ、ECDSAも人気を集めている
- Symmetric encryption algorithm: クライアントとサーバー間のデータを暗号化する方式で、AES-128-GCMやAES-256-GCMが例であり、AES-GCMは強力なセキュリティと効率を提供する
- MAC algorithm: メッセージの完全性と真正性を保証する方式で、HMAC-SHA256やHMAC-SHA384が例であり、HMAC-SHA256と最新cipher suiteのGCM modeが使われる
- クライアントとサーバーはcipher suiteに合意し、乱数seedとSSL certificate情報を交換して、メッセージの暗号化と検証に使う対称鍵を作成できる
- TLS handshakeの資料出典はCloudflareである
従来のTLS handshakeの段階
-
Client Hello
- クライアントが、サポートするcipher suite、対応TLS version、Client Randomという乱数を含んだTCPメッセージをサーバーに送る
-
Server Hello
- サーバーが、選択したTLS version、選択したcipher suiteアルゴリズム、Server Randomを含むTCPメッセージで応答する
-
Certificate Verification
- クライアントがCertificate Authorityを通じてサーバーのSSL certificateを検証し、サーバーのpublic keyを取得する
-
Premaster Secret Generation
- クライアントがpremaster secretを作成し、サーバーのpublic keyで暗号化してサーバーに送る
-
Decryption
- サーバーがprivate keyを使ってpremaster secretを復号する
-
Session Key Creation
- クライアントとサーバーがClient Random、Server Random、premaster secretを使ってsession keyを作る
-
Client Ready
- クライアントがsession keyで暗号化した
finished メッセージを送る
-
Server Ready
- サーバーがsession keyで暗号化した
finished メッセージを送る
-
Secure HTTP Communication
- 以後はsession keyを使った安全な対称暗号化によって双方が通信する
TLS 1.3で変わった点
- ここまで説明したTLS handshakeは元来のTLSバージョンに関するもので、最新のTLS 1.3基準では古い方式である
- TLS 1.3以降は、セキュリティ上の理由からRSAと複数のcipher suiteをサポートしない
- 最新バージョンは選択肢を大きく減らし、よりシンプルで、より安全で、より高速である
- TLS 1.3でも中核となる概念は維持されている
- handshakeを通じて圧縮方式、サーバー認証、鍵交換に合意する
- TCPを通じて交換されるパケットデータを保護するため、対称暗号鍵を生成する
- TLS 1.3は攻撃に弱いcipher suiteやパラメータをサポートせず、handshakeを短縮して、より高速で安全なhandshakeを実現する
-
TLS 1.3 handshakeの基本段階
- Client hello: クライアントがプロトコルバージョン、Client Random、cipher suiteの一覧を送る
- TLS 1.3では安全でないcipher suiteのサポートが削除され、利用可能なcipher suite数が大幅に減っている
- Client helloにはpremaster secret計算に使うパラメータも含まれる
- クライアントはサーバーが好むkey exchange methodを知っていると仮定しており、cipher suiteの一覧が減ったため、その可能性が高い
- この構造により、TLS 1.0、1.1、1.2のhandshakeより全体の長さが短くなる
- Server generates master secret: サーバーはClient Random、クライアントパラメータ、cipher suiteを受け取った状態で、Server Randomを自ら生成できるため、master secretを作成できる
- Server hello and
Finished: Server helloにはサーバーcertificate、digital signature、Server Random、選択されたcipher suiteが含まれる
- サーバーはすでにmaster secretを持っているため、
Finished メッセージも同時に送る
- Final steps and client
Finished: クライアントはsignatureとcertificateを検証し、master secretを生成した後、Finished メッセージを送る
- Secure symmetric encryption achieved: 以後、安全な対称暗号化が確立される
1件のコメント
Hacker News のコメント
専門家ではない者として疑問なのだが、特定のWebサイトやインターネット全体にアクセスできないとき、どの区間で障害が起きているのかがなぜこれほど分かりにくいのか分からない。
自分のローカルマシンのネットワーク設定ミスなのか、ルーターまでのWi-Fi接続の問題なのか、ルーターとISPの間のケーブル問題なのか、ISPの大規模障害なのか、アクセスしようとしているWebサイト側の障害なのかが、しばしば不明瞭。
リクエストが非決定的な経路でルーティングされるから、という漠然とした説明は聞いたことがあるが、説得力は弱い。経路上のどこかのリンクが切れたら、最後に正常だったリンクが「あなたのメッセージはここまでは届いたが、次の段階へ送ろうとして失敗した」と後ろへ知らせることはできないのか、と思う。
設定はまちまちで、どの構成が意図されたものなのか分からず、よくある原因に基づいて仮定した結果、完全に間違った答えを提示してしまうと危険。
例えばDNSサーバーも応答せず、対象ホストも応答しないなら、ルーター設定ミスやISP障害だと言えるかもしれないが、実際の原因はVPNクライアントがローカルのルーティングテーブルとDNSサーバーを変更したあと、終了時に元に戻せなかったことかもしれない。それが一時的な変更なのか永続的な設定なのかを、診断器がどうやって知るのかという問題。
アプリケーションはソケットをそのように設定していなければICMPメッセージを見られない。こうしたものは「一時的な」エラーとして扱われ、Linuxでは
IP_RECVERRソケットオプションで設定する。第7層で作業している場合、この層のエラーを収集しても価値は大きくない。上に現れるDestination Unreachableエラーは、すでに備えることになる失敗処理ロジックに合わせられるはずで、この場合ほかの層が到達不能な宛先に対して再試行するため、おそらくタイムアウトに見えるだろう。
TCP層がICMPエラーをどう処理するかについては、これらのRFCが役に立つ: https://www.rfc-editor.org/rfc/rfc1122#page-103
4.2.3.9では、Unreachableメッセージはsoft error条件なのでTCPは接続を中断してはならず、その情報をアプリケーションに提供すべきだとされている。TCPはERROR_REPORTルーチンでアプリケーション層へ渡すか、メッセージを記録しておき、TCP接続がタイムアウトしたときだけアプリケーションに報告できる。
TCP攻撃ベクターとしてのICMPを研究するため、スタック同士がどう相互作用するかをより詳しく扱った文書もある: https://www.rfc-editor.org/rfc/rfc5927
DNSサーバー自体に到達できないなら、ユーザーとそのサーバーの間のどこかのネットワークエラー。通常は各ステップを手動で実行して診断する。DNSサーバーのアドレスにpingが通るか、そのDNSサーバーで当該ホストを名前解決できるか、ほかのDNSサーバーではどうかを確認する。会社のポリシーにより特定の名前が除外されている場合もある。
さらに深掘りしたいなら、
ping、traceroute、digのようなコマンドラインツールが役に立つ。MTRはリアルタイムで動き続けるping + tracerouteのようなもので、各ホップが個別に表示される。
Xfinityネットワークでノードが死んでいることに初めて気づいたときも、同じMTRで少なくとも自分のネットワークからモデムまでは正常だと確認でき、一貫していた。ISPの向こう側のあるホップで遅延が数百ms増える様子も、MTRほどよく見せてくれるツールはあまり見たことがない。
すべての問題を解決するわけではないが、ホップごとに分けて遅延を提供してくれるので、確認してみる価値はある。
「問題はここだ」と言うには、OS、ハードウェア、ネットワークがどう構成されているかについての仮定が必要。
Webサイトに接続するときはまずDNSでWebサーバーのIPアドレスを取得する必要があるが、ブラウザがDNS IPをどこから得るのかの時点ですでに複雑。ブラウザ、OS、ルーター、モデムに設定することもでき、設定しなければルーターが接続したDHCPサーバーから受け取る。それがISPのDHCPサーバーかもしれないし、組織内部の別のルーターかもしれない。
DNSがおかしく見える場合、IPが間違っていることは分かりやすいが、そのIPがどこから来たのかを言うのは難しい。SSLも、サーバー証明書が間違っている場合もあれば、自分のコンピューターの証明書が間違っている場合もある。
関連するかもしれないが、TLSv1.2とTLSv1.3についてバイト単位で詳しく追える対話型の例もある。
TLSをもっと学びたいなら、本当に気に入っている資料なので強くおすすめする。
[0]: https://tls12.xargs.org/
[1]: https://tls13.xargs.org/
こういう観点で書かれた記事の例がもっとあるのか気になる。熟練度に関係なく、「そこそこのエンジニアに説明するように」かみ砕いた文章が好き
完全には明確でなかった断片を新しく学べたり、他人に説明するときに使える例をさらに得られたりするので、たいてい非常に役に立つ
例:
https://www.cloudflare.com/learning/dns/what-is-dns/
https://www.cloudflare.com/learning/ssl/transport-layer-secu...
https://www.cloudflare.com/learning/performance/what-is-http...
「クライアントが premaster secret を生成し、サーバーの公開鍵で暗号化してからサーバーに送る」という説明は、かなり前から事実ではない
いま説明した流れは、現代的な TLS 1.3 と比べると古い TLS 初期バージョンの手順だ、と付け加えられている
「現在の TLS バージョン(>1.3)はセキュリティ上の理由から RSA と複数の暗号スイートをサポートしていない」という話は、鍵交換の部分では正しい。RSA は前方秘匿性(forward secrecy)を提供しないため
署名には RSA が今でも使われており、おそらく x509 証明書で最も広く普及している種類だと思う
Safari も少し前に RSA 署名について 2048ビット鍵の要件を引き上げたと記憶している
この記事は実際の HTTPS 解説記事を AI が要約したように読める。用語が文脈なしに出てくる
証明書とは何か、信頼の連鎖がどう動くのかを説明せず、読者が公開鍵暗号を知っている前提になっている。OSI 7階層のうち6つを説明しているのに、その用語自体は言わず、プレゼンテーション層は抜けている
もちろんタイトルからして mediocre とは言っているが
文章を書くのが強みではないので、批判はありがたく受け止める。自分の文章が「ひどい」から「AI なのか?」に進んだのは進歩だ
説明をどこで区切るか悩んだし、公開鍵暗号はほかの場所でもっとよく説明できる良い境界だと考えた。OSI の複数の層についても同じだった
証明書と、ひょっとすると 信頼の連鎖全体は扱うべきだったという点は認める
SHA256(client_hello_random + server_hello_random + curve_info + public_key)の 署名検証を示すコードが見つからない理論は分かるが、実装しようとすると何か問題が起きる。実際にどうやるのかを示すおもちゃプログラムへのリンクがあるとありがたい
「サーバーの SSL 証明書に秘密鍵が入っている」式の表現でないことを本当に願う。それでもタイトルは「Mediocre Engineer」ではある
TLS <1.3 も記事で描写しているようには動かないのに、そこへ 1.3 のより新しい要素を混ぜようとしている。DNS の部分は再帰リゾルバを説明しているが、クライアントはそうは動かず、おそらくスタブリゾルバと通信するはず
「Internet Layer」、brotli が TLS 圧縮や暗号スイートで広く使われるアルゴリズムであるかのような示唆、「現在の TLS バージョン(>1.3)は RSA をサポートしない」といった誤りが次々に出てくる
こういう ブログスパムのせいで、ときどき downvote があればいいのにと思う。広告は flag するほど目障りではないが、レベルは低い。むしろ、もう少し mediocre でない記事を書いて HN のトップページに載せるべきかもしれない。年収30万ドルを稼いでいたなら、もっと時間があっただろうに
記事の内容は全体的に少し古い。最近の Web リクエストの 30% は HTTP/3 だし、CORS もあるのに、投稿日がない
私はふだん企業ネットワーク内にデプロイされる SaaS システムを開発しているが、CORS リクエストはほぼ0%に近い。HTTP/3 も同様