CONNECT が 200 を返し、TLS がすぐにデコードできないときは、証明書や暗号方式を変える前にコネクタの境界バイトを調べる。

生成された認証値がすでに改行で終わっていることがある。さらに改行を追加すると HTTP ヘッダーが早く終わり、意図した Host フィールドや他の平文がリクエストの後ろに残る。

最小の HTTP/1.1 CONNECT リクエストは、行間を CRLF、最後を空行で区切る。

b"CONNECT example.com:443 HTTP/1.1\r\nHost: example.com:443\r\n\r\n"

認証フィールドは最後の空行の前に置き、途中に改行を入れない。Python では "\n" が改行を表し、バックスラッシュと文字 n を含む raw 文字列は改行を表さない。除去する前に、エンコーディング用ヘルパーがどのバイトを生成するか確認する—古いヘルパーは改行を追加することがあった。

CONNECT が成功すると、残ったバイトはトンネルされたプロトコルのものになる。迷い込んだ平文は TLS を期待する相手に届くことがある。成功ステータスは、不正なリクエストの後にすでにキューに入ったバイトを修復できない。

受信側の境界も調べる。ソケットを TLS に渡す前にプロキシ応答を完全に読むようにし、部分的な読み取りを扱い、ヘッダーより後に読んだものも保持する。ソケットの 1 回の読み取りがメッセージ全体を含むとは限らない。

このパーサーを自分で持つ場合は、秘匿化したバイト表現とワイヤの文法を比べる。パスワードを隠しつつ、長さと行の境界は見えるようにしておく。プロキシ接続だけが必要なアプリケーションなら、保守されたコネクタを使えばこのフレーミングコードを自分で持たずに済む。

関連記事