HTTPプロキシを作成していますが、TLSを介したCONNECTリクエストの作成に関する詳細を理解できません。より良い状況を得るために、私はApacheを実験して、クライアントとどのように相互作用するかを観察しています。これは私のデフォルトの仮想ホストからのものです。
NameVirtualHost *:443
<VirtualHost>
ServerName example.com
DocumentRoot htdocs/example.com
ProxyRequests On
AllowConnect 22
SSLEngine on
SSLCertificateFile /root/ssl/example.com-startssl.pem
SSLCertificateKeyFile /root/ssl/example.com-startssl.key
SSLCertificateChainFile /root/ssl/sub.class1.server.ca.pem
SSLStrictSNIVHostCheck off
</VirtualHost>
Apacheと私のクライアントの間の会話はこのようになります。
a。クライアントはexample.com:443
に接続し、TLSハンドシェイクでexample.com
を送信します。
b。クライアントはHTTPリクエストを送信します。
CONNECT 192.168.1.1:22 HTTP/1.1
Host: example.com
Proxy-Connection: Keep-Alive
c。 ApacheはHTTP/1.1 400 Bad Request
と言います。 Apacheエラーログは言う
Hostname example.com provided via SNI and hostname 192.168.1.1
provided via HTTP are different.
HTTP/1.1がそれを要求するので、Apacheはそこにあることを確認する以外にホストヘッダーを調べないようです。クライアントがHost: foo
を送信した場合、同じ動作が失敗します。 TLSなしでexample.com:80にHTTPリクエストを送信すると、Apacheは192.168.1.1:22に接続します。
私はこの振る舞いを完全に理解していません。 CONNECTリクエストに問題がありますか?このすべてを説明するRFCの関連部分を見つけることができないようです。
Apache Httpdをプロキシサーバーとして使用するかどうかは明らかではありません。これは、取得する400ステータスコードの説明になります。 CONNECT
はクライアントによって使用され、宛先Webサーバーではなく、プロキシサーバー(おそらくApache Httpdですが、通常はそうではありません)に送信されます。
CONNECT
は、クライアントとエンドサーバー間のTLS接続を確立する前に、クライアントとプロキシサーバー間で使用されます。クライアント(C)はプロキシ(P)proxy.example.com
に接続し、このリクエストを送信します(空白行を含む):
C->P: CONNECT www.example.com:443 HTTP/1.1
C->P: Host: www.example.com:443
C->P:
プロキシはTCP www.example.com:443
(P-S)への接続]を開き、200ステータスコードでクライアントに応答し、リクエストを受け入れます。
P->C: 200 OK
P->C:
この後、クライアントとプロキシ(C-P)間の接続は開いたままになります。プロキシサーバーは、P-Sとの間のC-P接続のすべてを中継します。クライアントは、そのチャネルでTLSハンドシェイクを開始することにより、アクティブ(P-S)接続をSSL/TLS接続にアップグレードします。これですべてがサーバーに中継されるため、TLS交換がwww.example.com:443
で直接行われたかのようになります。
プロキシはハンドシェイクでは(したがってSNIでも)何の役割も果たしません。 TLSハンドシェイクは、クライアントとエンドサーバーの間で直接効果的に行われます。
プロキシサーバーを作成している場合、クライアントがHTTPSサーバーに接続できるようにするために必要なことはCONNECT
リクエストで読み取られ、プロキシからエンドサーバーへの接続を確立します(CONNECT
request)、クライアントに200 OK
応答を送信し、クライアントから読み取ったすべてのものをサーバーに転送します(逆も同様)。
RFC 2616 はCONNECT
を単純なトンネルを確立する方法として扱います(これがそのトンネルです)。詳細については RFC 2817 を参照してください。ただし、RFC 2817の残りの部分(非プロキシHTTP接続内でTLSにアップグレード)はほとんど使用されません。
クライアント(C)とプロキシ(P)の間でTLSを介して接続しようとしているようです。これは問題ありませんが、クライアントはCONNECT
を使用して外部のWebサーバーに接続しません(HTTPSサーバーへの接続でない限り)。
RFC 2616(セクション14.23)から:
Host request-headerフィールドは、リクエストされたリソースのインターネットホストとポート番号を指定します。これは、ユーザーまたは参照リソース(セクション3.2.2で説明されているように、通常はHTTP URL)によって与えられた元のURIから取得されます。 Hostフィールドの値は、元のURLで指定されたオリジンサーバーまたはゲートウェイの命名機関を表す必要があります。
私の理解では、CONNECT行からHost行にアドレスをコピーする必要があります。全体として、リソースのアドレスは192.168.1.1であり、example.com経由で接続しているという事実はRFCの観点からは何も変更しません。
あなたはすべてを正しく行っています。問題が発生したのはApacheです。 TLSを介したCONNECTのサポートは最近追加されただけで( https://issues.Apache.org/bugzilla/show_bug.cgi?id=29744 )、まだ解決されていないことがいくつかあります。あなたが直面している問題はそれらの1つです。
TLS(https)内にCONNECTメソッドが表示されることはほとんどありません。私は実際にそれを行うクライアントを知りません(そして、私はそれが誰であるかを知りたいので、それが実際に良い機能だと思います)。
通常、クライアントはhttp(プレーンtcp)を使用してプロキシに接続し、CONNECTメソッド(およびホストヘッダー)をHost:443に送信します。次に、プロキシはエンドポイントへの透過的な接続を行い、クライアントはSSLハンドシェイクを送信します。
このシナリオでは、データはsslで保護された「エンドツーエンド」です。
CONNECTメソッドは実際には指定されていません。HTTPRFCでのみ予約されています。ただし、通常は非常にシンプルであるため、相互運用が可能です。メソッドはHost [:port]を指定します。 Host:ヘッダーは単に無視できます。追加のプロキシ認証ヘッダーが必要になる場合があります。接続の本文が始まると、プロキシで解析を行う必要がなくなります(有効なSSLハンドシェイクをチェックするため、一部では解析が行われます)。