Proxy利用時のhttps通信のパケット(IPヘッダ、TCPヘッダ)に関して

戸根先生

「PC → Proxyサーバ → Webサーバ」の通信(HTTPS)についての質問です。

・設計・分析・管理のすべて
・ネットワークはなぜつながるのか 第2版
・完全理解 TCP/IPネットワーク

の3冊に関係する部分のご説明がありますが、
しっかりと理解出来ていないのでご質問させて頂きたいと思います。

■知りたいこと
 「PC → Proxyサーバ → Webサーバ」のHTTPS通信時に、
 パケットの中身がどうなっているかを知りたい。
 特に、宛先IPアドレスとTCPポート番号がどうなっているか?
 に関して理解したいです。

 ※以下の質問では、
  Proxyサーバは、TCP3128でリクエストを待っている。
  Webサーバは、TCP80(http)とTCP443(https)でリクエストを待っている
  という前提でお願いいたします。

■質問
「完全理解 TCP/IPネットワーク」をもとにご質問させて頂きたいと思います。
P293の図5-22のところです。

そもそものProxyを介したHTTPS通信の流れは、

1. PCがProxyに通信したい相手(Webサーバ)の情報を伝達する。(CONNECTコマンド)
2. ProxyがWebサーバとやり取りする。
3. ProxyがPCにWebサーバとの通信準備が整ったことを知らせる。
4. PCがWebサーバと通信する。ただしパケットはProxyを経由してからWebサーバに到達する。

というものだと思っておりますが、大筋で間違いはないでしょうか?

========== ここからが質問させて頂きたい内容です ==========

上記1~4の理解が間違っていないことが前提になりますが、

上記1の時、
 PC→Proxy向きのパケットの宛先IPアドレスは、ProxyのIPで、
 TCPのDestinationポート番号は、Proxyサーバのポート番号=3128。

 これで合っているでしょうか?

上記2の時、
 Proxy→Webサーバ向きのパケットの宛先IPは、WebサーバのIPで、
 TCPのDestinationポート番号は、Webサーバのポート番号=80。

 これで合っているでしょうか?
 sslのポート番号443ではなく、80を使うと考えています。

上記4の時、
 PC→Webサーバのパケットの宛先IPは、ProxyのIPで、
 TCPのDestinationポート番号は、sslのポート番号=443。

 ただしProxyサーバまでパケットが到着すると、
 Proxyは、宛先IPをWebサーバのものに書き換え、
 送信元IPは、自身のIPに書き換えて転送する。
 →TCPヘッダはノータッチで変更しない。

 これで合っているでしょうか?

 ここが一番、理解出来ていないところです。

よろしくお願いいたします。

名前: 
ネットワーク屋
日時: 
10/11/14 00:07

コメント

ネットワーク屋さん,おはようございます。

いただいた質問内容からの推測ですが,
ネットワーク屋さんは
ProxyがクライアントとWebサーバの間でパケットを転送する,
というようなイメージで考えているように見受けます。
もし,そうなら,そこが理解の妨げになっているように思います。

Proxyが転送するのはパケットではなく,TCPのコネクションの中を流れるデータです。
つまり,Proxyはクライアントとコネクションを張って,そこから届いたデータを受け取り,
それをアクセス先のWebサーバに転送するわけです。
その転送動作は,Webサーバとの間にコネクションを張って,
そこにクライアントから受け取ったデータをそのまま入れて送信する,
というイメージです。

別の角度から説明しましょう。
クライアントからProxyサーバに届いたパケットはProxyサーバが受け取り,
その中に入っているデータもProxyサーバが受け取ります。
IPとTCPの動作はここで終わりで,パケットはここで消滅する考えてよいでしょう。
そして,別のIPとTCPの動作によってProxyはWebサーバにデータを転送します。
つまり,Webサーバ宛のパケットを新たに作って,
そこにクライアントから受け取ったデータを入れて,Webサーバに送ります。
クライアントとProxy間のIPおよびTCPの動作と
ProxyとWebサーバ間のIPおよびTCPは全く別のものなのです。
付け加えると,パケットは1対1に対応しないかもしれません。
つまり,一つのパケットに入っていたデータが分割されて複数のパケットに入る,
あるいは,複数パケットのデータが一つのパケットに入るかもしれません。

ソケットのレベルで見ると次のような格好になります。
Proxyにはクライアントと接続したソケットとWebサーバと接続したソケットの二つがあり,
一方のソケットから受信したデータを他方のソケットから送信するという感じです。

それで,ポート番号はこんな感じになります。
Webサーバ(443番)<----->(*番)Proxy(3128番)<----->(*番)クライアント
(*番)はそのマシンの中でユニークなポート番号なら何でもよい

こんな説明でわかるかしら?

いつも丁寧に教えていただきまして本当にありがとうございます。

先生がおっしゃることと重複しているかもしれませんが、

「何が分かっていないか」がわかっていない
「何を勘違いしているか」がわかっていない

まま質問をさせていただいたようです。

クライアント <--> Proxy <--> Webサーバ

間におけるHTTP通信(tcp:80)においては、
ProxyサーバがTCPセッションを2つ持つことは理解しておりました。
つまりルータのL3レベルでの転送動作(ルーティング)とは異なる。

でも「HTTPSの場合もProxyは2つTCPセッションを持つの?」

というところがわかっていませんでした。

すみません。。
本来なら自分で調べてから質問させて頂くべきでしたが
今日パソコンでキャプチャーしてみてHTTPS通信時のパケットの中身を
確認してみました。

Webサーバ(443番)<----->(*番)Proxy(3128番)<----->(*番)クライアント

↑このようになっていることが確認できました。
 パソコン側でキャプチャしただけですので、
 クライアント-Proxy間のみの確認ですが、
 知りたかったのはここでしたので十分でした。

このキャプチャ結果を見たときに、

>Proxyが転送するのはパケットではなく,TCPのコネクションの中を流れるデータです。

の「データ」の意味する具体的なものが、
レイヤ4よりも上の部分=パケットのレイヤ5,6,7の部分のこと、
だとわかりました。

そして、HTTPSの場合もProxyは2つTCPセッションを持っている!

■勘違いしていたこと
 クライアント-Proxy間でtcp:3128を使用する(逆に言うとtcp:443を使用しない)
 のであれば、だれがSSLの処理(パケットの暗号化)をやるのか?
 クライアントがWebサーバとHTTPS通信をしたいのだから
 パケットの暗号化はクライアントが実施するに決まっている。

 だから、クライアント-Proxy間は、tcp:443のはずだ。<--ここを勘違いしていたようです

 と考えてしまっていました。

 クライアント-Proxy間も、Proxy-Webサーバ間もtcp:443を使っている。
 これがSSLトンネルの動作だろう。<--という勘違いとも連動していたようです

■理解できたこと1
 HTTPS通信の時もProxyサーバはTCPセッションを2つ持つ。

■理解できたこと2
 クライアント-Proxy間も、Proxy-Webサーバ間もプロトコルは同じHTTPSだが、
 tcp の Port番号は、
 3128(クライアント-Proxy間)、443(Proxy-Webサーバ間)であり、異なる。

結論として、このような理解であっているでしょうか?

ネットワーク屋さん,こんにちわ。

かなり理解が進んだように思いますが,
ちょっと惜しい部分もあるので補足します。

ネットワーク屋さんは通信動作のエンドっていうことを考えたことありますか?
つまり,一つの通信動作がどこで始まり,どこで終わるかという話です。
たとえば,下のようなネットワークでサーバからクライアントまでパケットを
運ぶ動作を考えてみましょう。

サーバ-----イーサネット-----ルータ-----イーサネット-----クライアント

まず,サーバからルータまでイーサネットでパケットを運びますよね。
このときのイーサネットの動作はルータで終わります。
だから,このイーサネットの動作はサーバとルータがエンドになります。
そして,新たにルータからクライアントまでイーサネットでパケットを運ぶ動作があり,
クライアントにパケットが届きます。
ここでのエンドはルータとクライアントです。

このように,イーサネットの観点で見ると通信動作はルータの両側で別々のものになりますが,
IPの観点から見ると,違った格好になります。
つまり,サーバからルータにパケットが届いたところでIPが終わるのではなく,
ルータで中継した後,クライアントに届いたところで終わります。
だから,IPのエンドはサーバとクライアントになります。

TCPとHTTPSの関係もこれと似ており,
TCPの方は二つの通信動作があり,そのエンドは
 WebサーバとProxy
 Proxyとクライアント
になります。(このエンドがソケットというわけです。)
ところがHTTPSの方は通信動作が一つで,Webサーバとクライアントがエンドになります。
HTTPSのデータはProxyに届いたところで終わりではなく,
そこから中継されてクライアント(あるいはWebサーバ)に
届いたところ終わることになります。
そして,HTTPSはエンドで暗号化と復号化を行いますから,
暗号を掛け,解くのはエンドのWebサーバとクライアントになり,
Proxy(SSLトンネル)は暗号化されたデータを単純に中継するだけ,
というわけです。

通信を理解するときは,このエンドという考え方が重要で,
これが分かると,一つ一つの技術的な要素を分解して考えられるようになります。
そして,複雑そうに見えるものでも,実は,
単純なものの組み合わせに過ぎない,ということがわかると思いますよ。

それから,

>「何が分かっていないか」がわかっていない
>「何を勘違いしているか」がわかっていない

わからないときっていうのは,そういうものですから,
気にすることはありません。
わかろうという気持ち重要で,それは伝わってきてますから,大丈夫ですよ。

詳しいご説明を頂き本当にありがとうございます。
TCPとHTTPSの関係のご説明で、さらに理解が深まったと感じます。

通信動作のエンドに関しては、
L2とL3の違いに関しては考えてきたことがあります。

L3とL4の違いに関しては最近理解が少しずつ深まりつつあり、

L4とそれ以上のレイヤに関しては、
いままでほとんど考えてきたことがありませんでした。
業務上必要とされる技術がL2とL3、FWを触る時はL4までですので
アプリレイヤのことを普段意識することがほとんどありません。

ですので、TCPとHTTPSをレイヤ別に捉えて
そのエンドの違いを意識して考えることは今までなかったです。

それが原因でなかなか理解できなかったのではないかと思います。
ご説明、ありがとうございました。

それと、もう1点、すいません。

クライアントが作成するHTTPSパケットのTCPヘッダの値
について思いついたことがあるのですが、

「そもそもクライアント側のブラウザーには、
 ProxyのIPアドレス(もしくはFQDN)とTCPポート番号を指定します。
 だから、クライアントが投げるHTTPSパケットのTCPヘッダには、
 ポート番号443がセットされるはずがない」

Proxyサーバ側の設定(たとえばsquid)で、ポート番号を443に指定して
リクエストを待つように設定することはまずないとすると
このように言い切れると感じました。

と思ったのですが、これは正しいでしょうか?

>「そもそもクライアント側のブラウザーには、
> ......
> ポート番号443がセットされるはずがない」

Proxy側で443を設定しなければ,クライアント側は443にはなりませんが,
Proxy側が443なら,クライアントは443にしないといけません。
そして,Proxy側を443にしてはいけない理由もありません。
(ProxyがHTTPSサーバと兼用ではないという前提ですけど)

ポート番号というのは,それ自身が意味を持っているわけではなく,
多数存在するソケットの中から特定のソケットを識別するために使う単なる番号に過ぎません。
つまり,まず,サーバ側(正確には接続を待ち受ける側)でソケットにポート番号を割り当て,
クライアント側(接続する側)でそのポート番号を設定しておくと,
TCPヘッダの宛先ポート番号欄にその番号を書いた制御パケットがクライアントから送信され,
それがサーバ側で受け付けられると両者が繋がるというだけのものです。
443でも他の番号でも何でもいいわけです。
事実,プログラムを書くときは何番にしてもかまいません。
(他のソケットに割り当て済の番号はダメですけど)

ただ,クライアントがその番号を知らないといけません。
サーバ側が何番で待ち受けているかわからないと,
クライアント側でポート番号をTCPヘッダに書けませんからね。
そこで,全世界でルールを設けて番号を決めておくわけです。
それが,HTTPだったら80,HTTPSだったら443というようなルールです。
(http://www.iana.org/assignments/port-numbers)

このルールは,サーバ側とクライアント側でポート番号を了解し合うためのものですが,
これ以外の方法で了解することもできます。
サーバ側とクライアント側を管理する人が一人なら,了解も何も不要でしょうし,
同じ社内にあるシステムであれば,口頭で伝えるなんて方法もあるでしょう。
そういう了解があれば,HTTPSは443といったルールに縛られずに他の番号を使うことができます。

話が少し別の方向に向かってしまいましたが,
ポート番号っていうのはそういうもので,
TCPコネクションの両側のエンドで了解していれば何番でもいいんです。
Proxyの場合はTCPが二つあるので,ちょっとだけ複雑に見えますが,TCP自身は何も変わりません。
そして,このTCPの考え方はProxyに限らず,どんなアプリケーションにも共通です。
というか,どんなアプリケーションであっても,TCP自身の動きが変わることはありません。
変わってしまったらTCPのルール(プロトコル)に反しますから。

こういうことを確認したかったのかなぁ,と勝手に判断しましたけど,当たってます?

再度丁寧なご回答を頂き本当にありがとうございます。
少々、質問がレベルダウン(もしくは逆戻り)したような印象になってしまいました。

①今回、HTTPS通信において、Proxyサーバを使う場合に
 クライアントはProxyがリッスンしているポート番号を
 TCPヘッダに設定する

ことをTCPとHTTPSの動作(レイヤ)の違いから
学ばせていただいたわけですが、

※このことは理解できてしまえば当たり前なのですが、
 理解できていないとき(つい先日まで)はこの当たり前の
 考えが持てませんでした。

上記①の理解を
別の角度からも知る(確認する、検証する)ことで
より①の理解を深く、間違えのないものにしたかったのです。

そこで「そもそも話」を持ち出させていただきました。

②クライアントがProxyに投げるパケットにおいては、
 ブラウザに設定したポート番号以外を使うわけがない。
 なぜなら、ブラウザに対して
 「このポート番号を使ってProxyにパケットを投げなさい」と指示していること
 になるわけですから、プロトコルがHTTPじゃなくてHTTPSだからといって、
 この指示したポート番号を使わず、なにか違う番号を勝手にチョイスして
 動作するなんてことは有り得ない。

ことを確認したかったのです。

①の理解を補強するために②も理解する。といった感じです。

すみません。
質問させて頂く順序が悪く話の流れが逆戻りしたようになってしまいました。。。