【図解】CONNECTメソッドとは?プロキシ経由のHTTPS通信の流れを初心者向けに解説

プロキシを経由してHTTPSのサイトを見るとき、PCとプロキシの間では CONNECT というリクエストが使われています。パケットキャプチャを取ると、最初に CONNECT www.example.com:443 が見え、そのあとはTLSの暗号化された通信が続きます。

ここでよくある誤解が「プロキシを通るHTTPSは、プロキシで一度復号されている」というものです。プロキシでTLSを復号する設定にしていなければ、TLSはPCとWebサーバの間で直接張られ、プロキシは暗号化されたデータを中継しているだけです。この記事では、CONNECTメソッドが何をしているのかを、TLS復号をしない場合とする場合のシーケンスで比べながら説明します。あわせて、プロキシ認証の407や、X-Forwarded-For・Forwarded・Via といったヘッダーとの関係も整理します。

この記事でわかること
  1. プロキシに送るリクエストの形(http:// と https:// の違い)
  2. CONNECTメソッドでトンネルを作る流れ
  3. TLS復号をしない場合とする場合で、何が違うのか
  4. 407とプロキシ認証(Proxy-Authenticate・Proxy-Authorization)
  5. X-Forwarded-For・Forwarded・Via は付くのか
この記事について

この記事は、HTTPの仕様(RFC 9110、RFC 9112 など)と、Squid、Microsoft、Chromium などが公開しているドキュメントを参考に、プロキシに共通する考え方をまとめたものです。特定の製品の動作を説明・保証するものではありません。実際の動作は、お使いのプロキシ製品のドキュメントで確認してください。

プロキシに送るリクエストは3つの形

HTTPのリクエストの1行目は、送る相手によって書き方が変わります。Webサーバに直接送るときはパスだけを書きますが、プロキシに送るときは、プロキシが「どこへ取りに行けばよいか」が分かるように書く必要があります。

直接アクセス(プロキシなし) パスだけを書く (origin-form) GET /index.html HTTP/1.1 Host: www.example.com プロキシ経由で http:// URLを丸ごと書く (absolute-form) GET http://www.example.com/index.html HTTP/1.1 Host: www.example.com プロキシ経由で https:// ホスト名:ポートだけ (authority-form) CONNECT www.example.com:443 HTTP/1.1 Host: www.example.com:443 https:// のときは、プロキシに「どのサーバとつなぐか」だけを伝え、URLの中身は渡さない
図1 リクエストの1行目の3つの形
場面1行目の形プロキシに分かること
直接アクセスパスだけ(GET /index.html)(プロキシを通らない)
プロキシ経由で http://URLを丸ごと(GET http://www.example.com/index.html)URL、ヘッダー、中身のすべて
プロキシ経由で https://ホスト名とポートだけ(CONNECT www.example.com:443)つなぐ先のホスト名とポートだけ

http:// のサイトなら、プロキシはリクエストの中身をすべて読めるので、代わりにWebサーバへ取りに行き、結果を返せます。https:// のサイトは中身が暗号化されているので、プロキシは代わりに取りに行けません。そこでPCは、プロキシに「この相手とつながる通り道(トンネル)だけ作ってほしい」と頼みます。これがCONNECTメソッドです。

CONNECTメソッドとは

CONNECTは、プロキシに「指定したホストのポートまで、TCPのトンネルを作ってほしい」と頼むメソッドです。プロキシは宛先に接続し、成功すれば 200 番台の応答を返します。そのあとは、PCとWebサーバの間を流れるデータを、中身を見ずにそのまま両方向へ中継します。

社員のPC プロキシ Webサーバ TCP①(プロキシの8080番など) TCP②(Webサーバの443番) TLS(暗号化)は PC と Webサーバ の間で1本 プロキシは2本のTCPのあいだでバイト列を受け渡すだけ。 中身(暗号化されたデータ)は見ない・変えない
図2 CONNECTで作るトンネルのイメージ

図2のとおり、TCPの接続はPCとプロキシ、プロキシとWebサーバの2本に分かれています。一方、TLSの暗号化はPCとWebサーバの間で1本だけです。プロキシは2本のTCPの間でバイト列を受け渡しているだけで、暗号化されたデータの中身は見ていません。

CONNECTのリクエストと応答の例

# PC → プロキシ
CONNECT www.example.com:443 HTTP/1.1
Host: www.example.com:443

# プロキシ → PC
HTTP/1.1 200 Connection established

# ここから先はトンネル(TLSのClientHelloが流れる)

CONNECTの決まりごと

項目内容
宛先の書き方「ホスト名:ポート」だけを書く。ポート番号は省略できない
リクエストの中身CONNECTのリクエストには本文がない
成功の応答200番台が返ると、応答のヘッダーの直後からトンネルになる。「Connection established」という文言は慣習で、決まっているのは番号だけ
失敗の応答200番台以外が返ったときは、トンネルはできていない
キャッシュCONNECTの応答はキャッシュされない
宛先ポートの制限どのポートにもつなげると、メール送信(25番)の踏み台などに悪用されるため、プロキシは接続できるポートを絞ることが求められている

シーケンスで見る:TLS復号をしない場合

プロキシでTLSを復号しない場合の流れです。CONNECTと200のやり取りのあとは、プロキシは中継するだけになります。

社員のPC ブラウザ プロキシ proxy:8080 Webサーバ www.example.com:443 TCP接続(8080番) 1 CONNECT www.example.com:443 2 接続してよい宛先か判断し、 名前解決もプロキシが行う TCP接続(443番) 3 200 Connection established 4 ここから先、プロキシはバイト列をそのまま中継する(トンネル) ClientHello(SNI: www.example.com) 5 ServerHello・証明書(TLS 1.3 では暗号化) 6 暗号化された GET /index.html 7 暗号化されたレスポンス 8
図3 TLS復号をしない場合のシーケンス

ポイントは、TLSのハンドシェイク(⑤⑥)がPCとWebサーバの間で行われていることです。PCが受け取るのはWebサーバの本物の証明書で、暗号の鍵もPCとWebサーバだけが持っています。GET /index.html のような実際のリクエスト(⑦)は暗号化されているので、プロキシには読めません。また、名前解決はプロキシが行うので、PCは宛先のIPアドレスを知らなくてもかまいません。

プロキシに見えるもの・見えないもの

情報プロキシに見えるか理由
宛先のホスト名とポート見えるCONNECTの1行目に書かれている
SNI(TLSで名乗るホスト名)見えるClientHelloの中で暗号化されずに送られる。ただし、ECH(Encrypted Client Hello)を使うと隠れる
サーバの証明書TLS 1.2 では見える、TLS 1.3 では見えないTLS 1.3 では証明書のやり取りも暗号化される
URLのパスやクエリ見えない暗号化されたリクエストの中にある
ヘッダー・Cookie・本文見えない同上
通信量・時間見える中継しているので、量と時間は分かる

URLフィルタがHTTPSのサイトを「ホスト名単位」でしか判断できないのはこのためです。パスまで見て判断したい、ファイルの中身を検査したい場合は、次のTLS復号が必要になります。

シーケンスで見る:TLS復号をする場合

プロキシでTLSを復号する(SSLインスペクション)場合も、PCが最初に送るのは同じCONNECTです。違いは200を返したあとで、プロキシがPCのTLSを自分で受け止め、Webサーバとは別にTLSを張ります。

TLS復号なし:TLSは1本(PC ⇔ Webサーバ) プロキシ TLS(Webサーバの本物の証明書) プロキシに見えるのは、宛先のホスト名とポート(CONNECTとSNI) TLS復号あり:TLSは2本(PC ⇔ プロキシ、プロキシ ⇔ Webサーバ) プロキシ TLS①(会社のCAの証明書) TLS②(本物の証明書) プロキシの中で一度復号されるので、URLや中身まで検査できる
図4 TLS復号なしは1本、復号ありは2本
社員のPC 会社のCAを信頼済み プロキシ TLS復号あり Webサーバ www.example.com:443 CONNECT www.example.com:443 1 200 Connection established 2 ClientHello(SNI: www.example.com) 3 ClientHello(プロキシが別にTLSを張る) 4 本物の証明書 5 本物の証明書をもとに、 会社のCAで署名した証明書をその場で作る プロキシが作った証明書 6 会社のCAを信頼しているので 警告は出ない GET /index.html(TLS①で暗号化) 7 復号してURL・中身を検査する GET /index.html(TLS②で暗号化) 8 レスポンス 9 検査したレスポンス 10
図5 TLS復号をする場合のシーケンス

プロキシは、Webサーバの本物の証明書をもとに、会社の認証局(CA)で署名した証明書をその場で作り、PCに渡します。PCは会社のCAを信頼するように設定されているので、警告は出ません。PCのブラウザで証明書を確認すると、発行者が会社のCAになっているのが目印です。

こうしてPCとプロキシの間(TLS①)、プロキシとWebサーバの間(TLS②)の2本のTLSになり、プロキシの中では通信が一度復号されます。URLのパスやファイルの中身まで検査できるのはこのためです。一方、証明書を固定している(ピンニングしている)アプリは、会社のCAの証明書を受け付けないので通信できなくなります。こうしたアプリは、復号の対象から外しておきます。

補足

同じ「プロキシ経由のHTTPS」でも、復号するかどうかはプロキシの設定で決まり、宛先ごとに変えられます。たとえば、金融機関や医療系のサイトは復号せずにトンネルのまま通す、という設定がよく使われます。

プロキシ認証と407

プロキシが「誰が使っているのか」を確かめる場合、最初のCONNECTに対して 407 Proxy Authentication Required を返します。PCは認証の情報を付けて、もう一度CONNECTを送ります。

ヘッダー・番号向き意味
407プロキシ → PCプロキシを使うには認証が必要、という応答
Proxy-Authenticateプロキシ → PC407に付けて、使える認証方式(Basic、Negotiate など)を伝える
Proxy-AuthorizationPC → プロキシ認証の情報を載せる。受け取ったプロキシが使い終わり、Webサーバには送られない

Webサーバ自身が認証を求めるときは 401・WWW-Authenticate・Authorization を使います。407の仲間は「プロキシ用」で、すぐ隣のプロキシとの間だけで使われる、と覚えると区別しやすくなります。

Basic認証の例

# プロキシ → PC
HTTP/1.1 407 Proxy Authentication Required
Proxy-Authenticate: Basic realm="corp-proxy"

# PC → プロキシ(ユーザー名:パスワードをBase64にしたもの)
CONNECT www.example.com:443 HTTP/1.1
Host: www.example.com:443
Proxy-Authorization: Basic dXNlcjE6cGFzc3dvcmQ=

Basic認証のBase64は暗号ではなく、誰でも元に戻せます。PCとプロキシの間が暗号化されていなければ、パスワードがネットワークに流れることになります。企業では、Active Directoryと連携したNegotiate(Kerberos)やNTLMがよく使われます。

NTLM・Negotiateでは407が何回か返る

NTLMやNegotiateは、同じTCP接続の上で何往復かやり取りして認証します。そのため、パケットキャプチャで407が2回続いても、異常ではありません。

社員のPC ブラウザ プロキシ 認証が必要 Webサーバ www.example.com:443 CONNECT www.example.com:443 1 407 Proxy Authentication Required Proxy-Authenticate: NTLM 2 CONNECT + Proxy-Authorization (NTLM:あいさつ) 3 407 + Proxy-Authenticate (NTLM:チャレンジ) 4 CONNECT + Proxy-Authorization (NTLM:チャレンジへの答え) 5 ユーザーを確認できた。認証の情報は ここで使い終わり、Webサーバには送らない TCP接続(443番) 6 200 Connection established 7 NTLMやNegotiateは、同じTCP接続の上で何往復かやり取りする。407が2回返るのは正常
図6 プロキシ認証の流れ(NTLMの例)

途中でTCP接続が切れると、認証を最初からやり直すことになります。プロキシや途中の機器がTCP接続を維持(キープアライブ)しないと、認証が終わらずに407が繰り返されることがあります。

X-Forwarded-For・Forwarded・Via はどうなるのか

プロキシを通ると、Webサーバから見た送信元のIPアドレスはプロキシになります。そこで、プロキシが元の送信元などをヘッダーに書き足す仕組みがあります。

ヘッダー内容位置づけ
Via経由したプロキシ(プロトコルのバージョンと名前)HTTPの仕様で、プロキシは付けることになっている
X-Forwarded-For元の送信元のIPアドレス仕様にはないが、広く使われている
Forwarded元の送信元・プロトコル・経由したプロキシなどRFC 7239 で標準化された、X-Forwarded-For の後継

大事なのは、これらのヘッダーを書き足せるのは、プロキシがHTTPのリクエストを読める場合だけだということです。CONNECTのトンネルの中を流れるHTTPSのリクエストは暗号化されているので、TLS復号をしないプロキシは、中のヘッダーを読むことも書き足すこともできません。

社員のPC IP: 10.0.10.25 プロキシ 名前: proxy1 IP: 10.0.0.8 Webサーバ http://(暗号化されていない) proxy1 GET /index.html HTTP/1.1 Via: 1.1 proxy1 X-Forwarded-For: 10.0.10.25 ← プロキシの名前 ← PCのIPアドレス → プロキシが付けられる https://・TLS復号なし proxy1 (暗号化されたデータ) プロキシは中のヘッダーを 読めない・書き足せない → 付けられない https://・TLS復号あり proxy1 GET /index.html HTTP/1.1 Via: 1.1 proxy1 X-Forwarded-For: 10.0.10.25 ← プロキシの名前 ← PCのIPアドレス → 設定しだいで付けられる Webサーバから見た送信元IPは、どの場合もプロキシの 10.0.0.8 になる
図7 X-Forwarded-For や Via が付くかどうか

図7では、社員のPCのIPアドレスを 10.0.10.25、プロキシの名前を proxy1(IPアドレスは 10.0.0.8)としています。Via: 1.1 proxy1 は「HTTP/1.1 で受け取り、proxy1 というプロキシを経由した」という意味で、X-Forwarded-For: 10.0.10.25 は元の送信元であるPCのIPアドレスです。Webサーバから見た通信の送信元は、どの場合もプロキシの 10.0.0.8 です。

場面ヘッダーを付けられるかWebサーバから見えるもの
http://(暗号化なし)付けられる送信元IPはプロキシ。X-Forwarded-For があれば元のIPも分かる
https://・TLS復号なし付けられない送信元IPはプロキシだけ。元のIPは分からない
https://・TLS復号あり設定しだいで付けられるhttp:// と同じ

X-Forwarded-For には社内のIPアドレスが入るので、社外のサイトに社内のアドレスを知らせたくない場合は、付けない設定や消す設定にすることもあります。また、Webサーバの側では、X-Forwarded-For は利用者が自分で書き換えられることを前提に、信頼できるプロキシから来た値だけを使います。

そのほか知っておくと役立つこと

接続できるポートの制限

多くのプロキシは、CONNECTで接続できる宛先のポートを、既定で443番などに絞っています。443番以外のポートを使うHTTPSのサイトや、プロキシ経由でメールを送ろうとしたときにつながらない場合は、この制限が原因のことがあります。その場合、プロキシは403などのエラーを返します。

プロキシが返す主なエラー

番号よくある原因
403プロキシのルールで禁止されている宛先やポート
407プロキシの認証が必要、または認証に失敗した
502・503・504プロキシから宛先のサーバにつながらない、応答がない(どの番号になるかは製品による)

WebSocket・HTTP/2・HTTP/3

項目内容
WebSocketブラウザがプロキシ経由で WebSocket(ws:// や wss://)につなぐときも、CONNECTでトンネルを作る
HTTP/2 のCONNECTHTTP/2 では、1本の接続の中の1つのストリームが1本のトンネルになる
HTTP/3(QUIC)QUICはUDPを使うので、通常のCONNECT(TCPのトンネル)には乗らない。プロキシを設定したブラウザは、TCPのHTTP/2やHTTP/1.1でつなぐ。UDPを中継するための CONNECT-UDP(RFC 9298)という仕組みもある
HTTPSプロキシPCとプロキシの間もTLSで暗号化する方式。CONNECTの宛先やプロキシ認証の情報も隠せる。中のトンネルには、さらにPCとWebサーバの間のTLSが通る

よくある誤解

誤解実際
プロキシを通るHTTPSは、プロキシで復号されているTLS復号の設定をしていなければ、TLSはPCとWebサーバの間で張られ、プロキシは中継するだけ
CONNECTのあと、プロキシがWebサーバとTLSを張るTLS復号なしなら、TLSのハンドシェイクをするのはPC自身。プロキシが張るのはTCPだけ
プロキシならHTTPSでもURLが全部見えるTLS復号なしで見えるのは、ホスト名とポートまで
X-Forwarded-For はプロキシが必ず付けるTLS復号なしのHTTPSでは、トンネルの中のリクエストに付けられない
407はWebサーバのエラープロキシからの「認証してください」という応答
407が何度も返るのは失敗しているNTLM・Negotiateでは、何往復かするのが正常

まとめ

CONNECTメソッドは、プロキシに「この相手までトンネルを作ってほしい」と頼むためのメソッドです。トンネルができたあと、TLSはPCとWebサーバの間で張られ、プロキシは中継するだけになります。TLS復号をする場合だけ、プロキシの中でTLSが2本に分かれ、中身を検査できるようになります。

TLS復号なしTLS復号あり
最初のリクエストCONNECT ホスト名:443CONNECT ホスト名:443
TLSの本数1本(PC ⇔ Webサーバ)2本(PC ⇔ プロキシ、プロキシ ⇔ Webサーバ)
PCが受け取る証明書Webサーバの本物の証明書会社のCAで署名した証明書
プロキシに見えるものホスト名・ポート・SNI・通信量URL・ヘッダー・中身まで
X-Forwarded-For・Via付けられない設定しだいで付けられる
プロキシ認証(407)どちらもCONNECTの段階で行う。Proxy-Authorization はプロキシで使い終わる

コメント