新たな DNS RR [HTTPS] と [SVCB]
DNS に以下の新たな RR (リソースレコード) が追加になる見込みです。(2021/8/2 現在は RFC draft)
- SVCB (type64) : 汎用的なサービス (LDAPs や SMTPs 等) の通信時に事前にネゴするための情報一式を掲載
- HTTPS (type65) : HTTPS の通信時に事前にネゴするための情報一式を掲載
HTTPS レコードの背景とメリット
ALPN (Application Layer Procotol Negotiation)
https 通信は http/2 (http version 2) までは TCP + TLS のスタックで通信されていました。
しかし http/1.0 および 1.1 はテキストベースのプロトコルなのに対し、http/2 はバイナリベースになっており、互換性がありません。
http/1.0 および 1.1 にしか対応していない Web サーバの場合、(ALPN でネゴすることなく) いきなり http/2 で通信されても解釈できずエラーになります。どのようなエラーになるかは実装次第ですが、以下の例では Web サーバが http/1.1 400 Bad Request を返し、その直後 TCP Reset を送信することを想定しました。
このケースでは送信者は "HTTP/1.1 400 Bad Request" を見て「http/1.1 には対応しているのだな」と推測できますが、通信としてはとても非効率です。さらにもし (Bad Request を送らず) いきなり TCP Reset しか送ってこない場合は http/2 に対応しているかどうかすら分かりませんので何度も http/2 で繋ぎに行くかもしれません。
そこで http/2 の場合は TLS handshake の最初のパケットである ClientHello に ALPN (Application Layer Protocol Negotiation) という extension (拡張属性) に http/2 であることを示す "h2" という文字列を乗せ、クライアント側が「http/2 を使いたい」ことをサーバ側に通知します。(実際には http/2 に限らず、利用可能なプロトコルのリストを載せます。)
サーバ側はその中から最適なものを選択します。例えば http/2 が最適であれば、 ServerHello に載せてクライアント側に「じゃあ http/2 で通信しようぜ」とネゴシエーションします。(http/2 において、SSL/TLS が事実上必須であることには、こういった背景もありました。)
http/1.1 と http/2 の非互換性問題はこの TLS の ALPN 拡張属性により事なきを得ましたが、では http/3 の場合はどうでしょうか?
http/3 の場合は UDP + QUIC のスタックなので http/3 に対応していないサーバは UDP/443 ポートを開放していないでしょう。そうなるとそもそも TLS のネゴシエーションまで辿り着けません。(実装としては UDP/443 と TCP/443 を短い時間で送出する、という対応が一般的か。だがいずれにせよ非効率。)
そこで DNS HTTPS レコードの出番です。事前に QUIC に対応しているかどうかを HTTPS レコードで確認することができます。
ちなみに、Cloudflare はいち早く HTTPS レコードに対応しており、www.cloudflare.com の HTTPS レコードをキャプチャすると以下のように見えます。
ALPN で対応しているプロトコルリストが見えます。また、IPv4 Hint, IPv6 Hint としてWeb サーバの IP アドレスも確認できます。
参考までに、dig コマンドの例を以下に示します。
[root@localhost ~]# dig www.cloudflare.com type65 @1.1.1.1
; <<>> DiG 9.11.26-RedHat-9.11.26-4.el8_4 <<>> www.cloudflare.com type65 @1.1.1.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19657
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;www.cloudflare.com. IN TYPE65
;; ANSWER SECTION:
www.cloudflare.com. 258 IN TYPE65 \# 76 000100000100150568332D32390568332D32380568332D3237026832 0004000868107B6068107C6000060020260647000000000000000000 68107B6026064700000000000000000068107C60
;; Query time: 72 msec
;; SERVER: 1.1.1.1#53(1.1.1.1)
;; WHEN: 月 8月 02 18:18:19 JST 2021
;; MSG SIZE rcvd: 135
さらに、dns のパケットキャプチャ (.pcap) を以下リンクから取得できます。前述の図の通り、Wireshark ではエンコードされたレコード本体を構造的に表示してくれます。
ECH (Encrypted ClientHello)
TLS handshake の最初のパケット ClientHello には重要な情報があります。それは SNI (Server Name Indication) という、宛先ホストの FQDN を示すものです。
UTM は https 通信を FQDN で制御することができますが、それはこの SNI を見ているためです。以下は、当サイトへの接続時の Client Hello に記載された SNI の例です。
最下部で Server Name: milestone-of-se.nesuke.com となっているのが分かります。
しかし最近の動向として、この SNI を暗号化しよう、という動きがあります。それが ECH (Encrypted ClientHello) です。以前は ESNI (Encrypted SNI) と呼ばれていました。ECH は SNI だけでなく、ALPN 等も含め、ClientHello を全て暗号化しよう、という試みです。
TLS 1.3 以降は ClientHello と ServerHello の後 (サーバ証明書を提示する Certificate 等) は暗号化するようになりましたが、ClientHello と ServerHello で鍵交換をするため、この部分はどうしても暗号化できませんでした。
ECH では何かしらの方法で ECH 用のパラメータを事前設定もしくは取得し、そのパラメータを使って暗号化します。この取得する方法の 1 つとして HTTPS レコードがあります。
ECH では HPKE (Hybrid Public Key Encryption) という方式で共通鍵を生成し、AEAD で暗号化/メッセージ認証をします。 (2021/8/2 現在は RFC draft: https://www.ietf.org/archive/id/draft-irtf-cfrg-hpke-10.html)
DNS の HTTPS レコードには public key を埋め込む、ということなので RSA を使うのかと思いきや、HPKE の draft を見ると、非対話式 (non-interactive) の DH (Diffie-Hellman) を使うようです。OpenPGP や S/MIME で使われるケースのある、いわゆる Static DH のことかと思われます。
DH(skX, pkY): Perform a non-interactive Diffie-Hellman exchange using the private key skX and public key pkY to produce a Diffie-Hellman shared secret of length Ndh.
RSA も Static DH も TLS 1.3 での鍵交換方式として廃止されましたが、Client Hello の暗号化に関しては妥協して PFS (Perfect Foward Secrecy) の無い方式としたのでしょう。
HPKE の 9 章に以下の記載があります。
HPKE ciphertexts are not forward secret with respect to recipient compromise in any mode. This means that compromise of long-term recipient secrets allows an attacker to decrypt past ciphertexts encrypted under said secrets. This is because only long-term secrets are used on the side of the recipient.
HTTPS のその他のメリット
HTTPS レコードを使うと、事前に HTTP/3 を使うのか HTTP/2 を使うのか、http/1.1 しか使えないのか、ということが分かったり、ECH の公開鍵の取得ができる、ということが分かりました。
その他にも以下のようなメリットがあります。
ポート番号
たまに 8443 を待ち受けポートにしている Web サイト等がありますが、TCP,UDP のポート情報を HTTPS レコードに記載することができます。
これにより、URL記述で :8443 等としなくても自動でブラウザが調整してくれるようになるでしょう。
HSTS 対応
Web サーバが HSTS (HTTP Strict Transport Security) に対応しているかどうかを把握できます。わざわざ http リダイレクトを使わずとも、ブラウザが http から https への書き換えを自動で調整してくれるようになるでしょう。
ゾーン頂点など他レコードと重複する別名としての利用
CNAME レコードではその制約として、同名の他レコードが存在している場合は利用できません。ゾーン頂点には SOA レコードと NS レコードが存在するため、例えば example.com というゾーン内で、example.com という CNAME を作成することができませんでした。
ですが、HTTPS レコードを使えばその制約は無く、example.com という別名を使うことができます。
Encrypted ClientHello の仕組みとシーケンス
Encrypted ClientHello では互換性を保つため、Outer ClientHello (今まで通りの ClientHello, 平文) と Inner ClientHello (暗号化した encrypted_client_hello extension) として定義し、ECH に対応していない場合は今まで通りの処理で Outer ClientHello を使い通信ができるようにします。
つまり、秘匿したいドメイン名 (private ドメイン名) とは別に、通称のような仮のドメイン名 (public ドメイン名) が必要になります。それぞれ Inner ClientHello (暗号化) と Outer ClientHello (平文) に含まれます。
トポロジとしては「Shared Mode」と「Split Mode」の2つのモードがあります。
Shared Mode は Split Mode のうち Client-Facing Server と Backend Server が同一になるだけですので、まずは Split Mode での説明を行います。
- クライアントはまず HTTPS レコードを引き、static DH 公開鍵など、各種パラメータを取得します。HTTPS レコードを引いた結果の IP アドレスは Client-Facing Server を指します。
- クライアントは Static DH 公開鍵と自身の生成した DH 公開鍵/秘密鍵を使って共通鍵を生成し、ClientHello を暗号化し、"Inner ClientHello" として encrypted_client_hello extension の中に格納します。クライアントはさらに "Outer ClientHello" を生成し、encrypted_client_hello extension に加え、public ドメイン名の SNI を格納した server_name extension 等を付与します。
- クライアントは、暗号化した Inner ClientHello を含んだ Outer ClientHello を Client-Facing Server へ送付します。
- Client-Facing Server は Inner ClientHello (ECH) を復号し、問題なければ Inner ClientHello を通常の ClientHello としてバックエンドサーバへ中継します。(Outer ClientHello は取り外し)
- バックエンドサーバは 受け取った Inner ClientHello を通常のシーケンスで処理します。
もし ECH を復号できない場合は「ECH Reject」を返し、handshake を終了します。
なお、もし HTTPS で指し示した IP アドレスの Web サーバが ECH に対応しておらず、public 名でのサーバ証明書を保有している場合は、Outer ClientHello を使い、正常の https 接続が可能になります。
コメント