Google Public DNS over HTTPS を試す
2016年08月15日 月曜日
CONTENTS
【2018/11/16 追記】 本記事は、2016 年 4 月に Google Public DNS サーバに実装された、実験的な DNS over HTTPS プロトコルについて紹介しています。DNS over HTTPS プロトコルはその後 IETF の doh ワーキンググループにて標準化が進められ、2年半後の 2018 年 10 月に RFC8484 として出版されました。本記事で紹介したプロトコルは RFC8484 に規定されたプロトコルとはいくつもの点で異なっていることにご注意ください。 |
---|
こんにちは、IIJ の佐原です。普段は ルータ製品 の開発をしています。今回は業務からちょっと離れて、とある DNS サービスについて調べてみました。
Google Public DNS over HTTPS
Google Inc. が公開 DNS サーバを運営していることはご存知でしょうか? Google Public DNS と呼ばれるこの公開 DNS サーバは、”8.8.8.8″ という特徴的な IP アドレスで全世界のインターネットユーザに対して無料の DNS サーバ(フルレゾルバ)を提供してくれています。
そしてこの 4 月、Google Public DNS は HTTPS でもサービスを提供するようになりました。「DNS と HTTPS は全然別のプロトコルなのにどうやって?」と思われるかもしれません。その手法は独自のもので、Google Inc. は “DNS-over-HTTPS” と呼んでいます。かんたんに言うと、DNS プロトコルで運ばれる内容をほぼそのまま JSON にマッピングした RESTful API です。API の詳細は https://developers.google.com/speed/public-dns/docs/dns-over-https に公開されています。
HTTPS に載せる意味
“DNS-over-HTTPS” は API としての利用を意図したものですが、ブラウザからでもかんたんに試すことができます。たとえば、
https://dns.google.com/resolve?name=www.iij.ad.jp&type=A
にアクセスすると、ドメイン名 “www.iij.ad.jp” の “A” レコードを索いた結果が以下のような JSON 形式で返ってきます。内容を良く見ると、既存の DNS プロトコルでやりとりされているものとほぼ同等の情報が入っていることがわかります。
{
"Status": 0,
"TC": false,
"RD": true,
"RA": true,
"AD": true,
"CD": false,
"Question": [
{
"name": "www.iij.ad.jp.",
"type": 1
}
],
"Answer": [
{
"name": "www.iij.ad.jp.",
"type": 1,
"TTL": 252,
"data": "202.232.2.164"
}
]
}
では、従来の UDP/TCP ベースの DNS プロトコルの代わりに DNS-over-HTTPS を使う理由は何でしょうか。それはずばりセキュリティです。インターネット上の通信内容の大部分を占めるウェブの通信は、HTTP から HTTPS (TLS) に移行することで盗み見や改竄への危険に対処してきました。しかし HTTPS 通信を開始する前の段階で発生する DNS の通信は、いまだに暗号化されておらず、なりすましにも脆弱です。 DNS-over-HTTPS は HTTPS (TLS) という安全性が良く知られたプロトコルを DNS に適用することでこの問題の解決を試みています。
ところで、DNS のセキュリティプロトコルと言えば “DNSSEC” が有名です。DNS-over-HTTPS があれば DNSSEC は不要なのかというと、そんなことはありません。DNS-over-HTTPS と DNSSEC は組み合わせて使うことでお互いの弱点を補完し合う関係にあります。
- DNSSEC は主に DNS サーバ間(フルレゾルバと権威サーバの間)で利用され、DNS レコードが改竄されていないことを保証する。
- DNS-over-HTTPS はクライアント PC と DNS サーバ間(スタブレゾルバとフルレゾルバの間)での利用が意図されており、問い合わせ内容(DNSレコード)の秘匿と改竄防止、通信相手(DNSサーバ)のなりすましの防止を提供する。
実際に、Google Public DNS over HTTPS のサーバは DNSSEC の検証を行っているため、Google Public DNS over HTTPS を使えば自動的に DNSSEC の恩恵も受けることができます。
オーバーヘッドはどのくらい?
私がこの “Google Public DNS over HTTPS” サービスのリリースを見た時にはじめに考えたのは、「UDP ベースの通常の DNS プロトコルにくらべてどのくらい遅いのだろう?」ということでした。HTTPS を使っている以上、暗号化処理の分だけ余計に時間がかかることが想定されます。そして暗号化以外にも TCP/TLS のセッション管理、HTTP ヘッダの処理や JSON のデコードなど、UDP 上の DNS よりも遅くなりそうな要素がいくつもあります。そこで、実際にどのくらいの違いになるかを計ってみることにしました。
試験構成は下図のようにしました。
まず通常の UDP の DNS クエリを DNS-over-HTTPS で投げ直す DNS プロキシを実装し、条件を揃えるために UDP のクエリを単に転送する機能も追加しました。そして PC からそれらのプロキシに対して UDP のクエリを投げ、8.8.8.8 または dns.google.com を介してインターネット上の DNS サーバ(A,B,C,…)が保持するドメインを解決し、クエリの送信からレスポンスの受信までの時間を計りました。DNS クエリのデータセットには、私の自宅で発生した DNS のクエリを一定期間収集したものを使いました。
今回書いた DNS-over-HTTPS プロキシでは、起動時に TLS 上の HTTP/1.1 セッションを確立し、セッションを維持し続けた状態で DNS-over-HTTPS のリクエストを流すようにしました。これは、TCP/TLS/HTTPS のセッション確立にかかる時間を測定結果から除外するためです。試験を行うにあたっての仮定として一定量のクエリが継続的に発生する環境を想定し、そのような環境での自然な実装を選択しました。また HTTP/1.1 セッションを複数張ったり HTTP/2 を使うことでリクエストを並列化すればスループットを向上できると考えられますが、今回の試験ではその検証は対象外として DNS クエリは直列に送信することにしました。
不思議な実験結果
実験結果は以下のようになりました。
横軸が解決にかかった時間(10ミリ秒単位で切り捨て)、縦軸がクエリの件数(個)です。緑色が UDP で 8.8.8.8 に問い合わせたケース、橙色が DNS-over-HTTPS API に問い合わせたケースです。なお、処理時間が長くかかった方から上位 5% は省いてあります。
緑と橙のグラフが同じ形をしていて、かつ一定の間隔だけ右にずれていれば「HTTPS では UDP に比べて N ミリ秒のオーバーヘッドが観測されました。」と言えたところですが、予想に反して説明しにくいグラフが得られました。以下、このような結果になった理由を考えてみます。
グラフを見ると、まず UDP のクエリの個数を表す緑の棒が 0ms のところに高く出ていて、少し空けて 40ms のところにその半分ほどの緑の棒が立っているのが目につきます。もっとも早く応答が返っている 0ms の棒は、8.8.8.8 サーバが持つキャッシュにヒットしたケースでしょう。そしてキャッシュミスが発生した場合は 40ms 以上の処理遅延が発生したのだと考えられます。
一方、HTTPS のクエリを表す橙の棒は 40ms 以上にのみ計数されています。つまり HTTPS のクエリの処理には少なくとも 40ms かかっています。しかし単純に HTTPS の処理遅延が 40ms なのだと考えると、UDP では 10-30ms で解決されているクエリがひとつも無いのに対して HTTPS では 50-70ms で解決されているクエリがいくつも見られるのは奇妙です。
ここで、UDP のキャッシュミス時の遅延時間と HTTPS の最小の遅延時間がともに 40ms であることを見た同僚から「HTTPS の方にはキャッシュ機構が無いのではないか?」という指摘を受けました。そこで、あるドメインの権威サーバでパケットキャプチャをしかけつつ、DNS-over-HTTPS でそのドメインを解決させてみました。キャッシュ機構が無いのであれば、ドメインを解決させるたびに権威サーバまでクエリが来るはずです。しかし、必ずしも権威サーバまでクエリはやってきません。何らかのキャッシュはされていると考える方が妥当です。
やはり、UDP の 10-30ms 区間にクエリがまったく計数されていないのが気になります。キャッシュミスしたからといって必ず 40ms かかるのもおかしな話です。Google Public DNS の内部構造はわかりませんが、権威サーバへの問い合わせにそんなに時間がかかるような実装になっているとはとても思えません。40ms を地理的な距離に換算すると、日本を離れて台湾あたりまで行けてしまう程度の遅延です。もし、台湾に二次キャッシュがあって、8.8.8.8 サーバが持っている一次キャッシュにミスした場合は台湾の二次キャッシュまで聞きに行っていると仮定すると、40ms で解決されているクエリが妙に多い説明がつきます。
あれこれ調べているうちに、Google Public DNS の内部構造について調査した論文 (PDF) を見つけました。オランダのアムステルダム大学の研究報告です。この論文では、Google Public DNS は一次キャッシュと二次キャッシュの二段階のキャッシュ階層があると述べられています。そして Google Public DNS のドキュメント を見直すと確かに “In Google Public DNS, we have two levels of caching.” と書いてありました。ドキュメントには二次キャッシュの位置は書いていないためあくまで推測の域は出ませんが、40ms は台湾にある二次キャッシュまでの通信遅延であると考えて良さそうです。
これらをふまえると、HTTPS のクエリが常に 40ms 以上かかっているのは「HTTPS での問い合わせはすべて台湾の二次キャッシュに転送されている」という仮説で説明がつきます。また 80ms 付近にも小さな山があることにも理由が付けられます。実験に使ったデータセットは私の自宅で発生したクエリですから、日本国内にある権威サーバへの問い合わせが多めに含まれます。その場合はクエリが日本-台湾間を二往復することになり、したがって日本-台湾間の通信遅延の二倍の時間、40ms x 2 = 80ms 付近が多めに出てくるのも当然の帰結です。
台湾で再試験
さて、「HTTPS での問い合わせはすべて台湾の二次キャッシュに転送されている」という仮説が正しければ、台湾の国内から同じ測定をすれば 40ms の通信遅延がほぼゼロになるはずです。それを確認するため、台湾にあるクラウドサービスを使って同じ計測をしてみました。結果のグラフが下図になります。
見ての通り、40ms の遅延がきれいに無くなりました。「HTTPS での問い合わせはすべて台湾の二次キャッシュに転送されている」との仮説を補強する結果です。そして UDP(緑) と HTTPS(橙) で比べると、HTTPS のグラフは UDP のグラフを右にずらしたようなかたちになっています。その差が UDP に対する DNS-over-HTTPS のオーバーヘッドなのでしょう。
安全性とコストのトレードオフ
今回の実験ではキャッシュの影響が強く表れたため、「どのくらい遅いのだろう?」という当初の疑問にはなんとも答えにくい結果が出てきました。それでもあえて平均的にはどうなのかを見てみると、日本での測定結果の中央値は UDP で 47ms、HTTPS で 53ms でした。その差は 6ms、比率にすると 12% ほどです。少し、遅くなっています。
一方、台湾での実験では中央値の差はたったの 2ms でした。これだけオーバーヘッドが小さければ、DNS-over-HTTPS を使うことで得られるプライバシーや安全上のメリットが遅延増加のデメリットを十分に上回っているのではないでしょうか。
実験の結果、プロトコルとして見たときの DNS-over-HTTPS は UDP ベースの既存の DNS プロトコルと比べて遜色のない性能を出せるポテンシャルを持っていることがわかりました。今回紹介した Google Public DNS over HTTPS の他にも、インターネットの標準化団体 IETF では DNS プロトコルをそのまま TLS に乗せてしまう提案 RFC7858 や DTLS に載せる提案 draft-ietf-dprive-dnsodtls の標準化作業が進められています。どのような方式が主流になるかはまだわかりませんが、セキュリティの強化された DNS プロトコルが広く使われるようになる日はそう遠くないかもしれません。