TLS 1.3 は今もサーバー名を平文で送る
TLS 1.3 はハンドシェイクを暗号化するが SNI は暗号化しない。ClientHello を読み、本物の ECH 受け入れを確認し、観測者が今も見られるものを記録してほしい。
リスナーを TLS 1.3 に上げても、観測者が読めるものは変わるが、バージョン番号が示唆するほどではない。ClientHello は今も暗号化の交渉より前に送られ、通常の接続では要求したサーバー名が平文のままそこにある。Encrypted Client Hello はそれを隠す仕組みであり、独自の前提を持つ別個の配備だ。どちらの挙動を前提にするにせよ、ポリシーを書く前にこの四つの手順を実行してほしい。
ハンドシェイクが実際に何を露出するか
TLS 1.3 はサーバーの証明書と、ServerHello に続くハンドシェイクの大部分を暗号化する。クライアントが最初に送るものは、鍵がまだ存在しないため、その保護の外にある。サーバー名表示はその最初のフライトの一部であり、だからこそ受動的な観測者は何も壊さずに読める。
ECH 仕様(RFC 9849)は、協力するサーバー向けに内側の ClientHello を暗号化することでこれを変える。外側のハンドシェイクは残り、ネットワークが見られる公開名を運ぶので、配備には中間装置にとって意味のある外側の識別子が依然として必要だ。その外側の名前こそ、接続が匿名になると期待する人が見落とす部分である。それは隠された名前ではなく覆いの名前であり、他の名前と同じように解決され認証されなければならない。
これらはいずれも配送経路を隠さない。 送信元と宛先のアドレス、ポート、パケットサイズ、タイミングは依然として観測でき、多くの場合、名前よりも誰が話しているかをよく示す。名前解決とアプリケーション層の関係はさらに別の層であり、それぞれに独自の可視性がある。
思い込まずに ClientHello を読む
ServerHello のバージョンは、クライアントが何を送ったかを教えてくれない。関心のある観測者を代表する位置から、最初のフライトを直接見てほしい。
openssl s_client -connect app.plant.example:443 -servername app.plant.example -tls1_3 </dev/null> 2>/dev/null | head -20 sudo tcpdump -ni eth0 -c 40 'tcp port 443' -w /tmp/tls.pcap tshark -r /tmp/tls.pcap -Y 'tls.handshake.extensions_server_name' -T fields -e tls.handshake.extensions_server_name
最初のコマンドはハンドシェイクを行い、プロトコルのバージョンと要求した名前を含む交渉済みパラメーターを表示する。二番目は実際の接続の最初のパケットを取得し、三番目はそのキャプチャから SNI フィールドを取り出す。フィールドに値が入っていれば、エミュレートした観測者はそれを読める。
両者が食い違うときは、後で中間装置が書き換えたり落としたりする名前をローカルの取得が映しうるため、クライアント側と経路上で別々に取得する。TLS を自分で終端しないホストからも取得してほしい(終端するプロキシは設計上平文を見るので、ネットワークが見ているものについては何も証明しない)。
ECH 拡張は主張であって証拠ではない
ClientHello に ECH 拡張が見えるからといって、その接続が ECH を使ったとは限らない。クライアントは使える設定がないとき、まさにハンドシェイクを揃って見せるために GREASE ECH を送る。拡張はあり、内側の hello はおとりで、実際の名前は依然として読める。
dig +short HTTPS app.plant.example openssl s_client -connect app.plant.example:443 -tls1_3 -status </dev/null> 2>/dev/null | grep -i -E 'ech|status_request'
最初のコマンドは、オリジンが ECH 設定パラメーター付きの HTTPS リソースレコードを公開しているかどうかを示し、クライアントはそうやって鍵を学ぶ。二番目はハンドシェイクの状態情報を探すが、クライアントの成功メッセージのほうが強い証拠だ。重要なのは受け入れであり、対応する鍵を持たないサーバーは内側の hello を復号できず、接続は後退する。
ブラウザーの対応と設定はバージョンやプラットフォームで異なるため、クライアントも確認してほしい。「現代のブラウザーは ECH を使う」という前提のポリシーは、ある群れについての推測であって、あなたの群れについての事実ではない。実際に接続するバージョンを棚卸しし、それぞれから一つずつ試す。現在のデスクトップブラウザーで動く同じページが、同じネットワーク上の古いクライアントには何も隠せないかもしれない。
観測者の範囲をポリシーに書く
ある制御が何に依拠できるかを決める前に、観測者がどこに座り、その地点で何が見えるかを述べる。ブラウザーからサイトへの接続、外側の VPN 輸送、TLS を終端するプロキシは、それぞれ異なる事実の集合を露出し、ある位置のために書かれた規則が別の位置へきれいに移ることはまれだ。
制御が SNI の読み取りに依存するなら、ECH が使えるときと使えないときで、配備済みのクライアントがどう振る舞うかを試す。そのうえで、黙って一致しなくなるフィルターは決して配備されなかったフィルターより悪いという互換性の帰結を記録してほしい。
最後に、不確実さを記録に残す。古い普遍的な主張を新しいもので置き換えても、同じ隙間が別のプロトコル名の下に残るだけで、次のレビュアーも同じくらい固くそれを信じる。