最近のDNSのセキュリティー事情(DOH, DNSSEC, ESNI, TLS1.3)

#1. はじめに

最近、Cloudflare社の以下のDNS Securityチェック機能を知った。結果は以下の通りで、全然自分の環境は守られていなかったw 。興味をもったので、具体的にどういうSecurity Issueがあるのかをまとめてみた。

https://www.cloudflare.com/ssl/encrypted-sni/#dns-info
<img width="970" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/667dcfec-e693-61cc-3a51-408fb833da0a.png">

#2. Web通信(HTTPS)の概要

<img width="698" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/e20850c2-31ad-e40b-6e0d-d9833392206f.png">

Webサーバーに通信する時には、すごくラフに書くと以下のフローになる。なお、便宜上の説明として`https://www.example.com/news/index.html` というURLがあった場合に、

- `www.example.com`の箇所をFQDN
- `/news/index.html`の箇所をPATH

と呼ぶことにする。


##1. 名前解決の依頼

###課題
クライアントはFQDNの名前解決をCache DNSに依頼するが、一般的にこの問い合わせ依頼は**暗号化されていない**。つまり、どのPATHにアクセスしてどういうコンテンツを見ようとしているかまでは分からないが、どのFQDNにアクセスしようとしているかは第三者にわかってしまう。

###解決策
このCache DNSへの問い合わせを暗号化する。方式としては

- DNS over HTTPS(DoH)
- DNS over TLS(DoT)

が存在する。特にDNS over HTTPSは、[アメリカ国内のFirefoxユーザーに対してDoHをデフォルトで有効にするという発表](https://gigazine.net/news/20200226-firefox-dns-over-https-default-us/)もあり、アメリカ国外のユーザーも設定から簡単に有効化できるようになったので、利用に対して大分敷居が大分下がったように思える。

##2. Cache DNSによる名前解決の実施

###課題1
Cache DNSは権威DNSからAレコード(IPアドレス）を取得するが、レコード取得の際にキャッシュポイズニングなどによって、正規でない権威DNSから偽装されたレコードを登録してしまう可能性があった。

###解決策1
DNSSECを利用する。電子署名の仕組みを使い、Cache DNSが問い合わせにより得た応答が、本来の権威ネームサーバからの応答かどうか、パケット内容が改ざんされていないかどうか、さらに、問い合わせたレコードが存在するか否か、などを検証することができる。

###課題2
そもそも、マルウェアやアダルトコンテンツなど不適切なサイトのFQDNはCache DNSが名前解決しないようにしておきたい。

###解決策2
[Cloudflare社の新たな発表](https://blog.cloudflare.com/introducing-1-1-1-1-for-families/)によると、

- (IPv4)1.1.1.2/1.0.0.2 : Malwareブロッキング
- (IPv4)1.1.1.3/1.0.0.3 : Malwareとアダルトコンテンツのブロッキング
- (IPv6)2606:4700:4700::1112/2606:4700:4700::1002: Malwareブロッキング
- (IPv6)2606:4700:4700::11132606:4700:4700::1003 : Malwareとアダルトコンテンツのブロッキング

がされているDNSとして利用できる。これらのDNSを利用してアダルトサイトなどにアクセスした場合は、無効、不明、適用外を示す0.0.0.0が返ってくる。

※なお、IBMも同様のQuad9と呼ばれるDNS サーバーを無償提供しているようだ。[こちらの記事](https://www.ibm.com/blogs/security/jp-ja/tele-work-security-quad9/)によると、IBM X-Force を始めとする 19の異なる脅威インテリジェンス・パートナーから得られたドメインのリストに対してサイトをチェックしてくれているため、既知の悪意のあるドメインをブロックし、デバイスがマルウェアやフィッシング・サイトに接続するのを防いでくれるとのこと。


##3. TLS session（その１）

###課題
Cache DNSより取得したIPアドレスを使ってクライアントはWebサーバーと通信するが、いきなり最初から全ての通信が暗号化されるわけではなく、まずはTLS sessionを張ってWebサーバーから送付してもらった証明書を確認したり、この後の暗号化通信のための鍵交換といった事前準備を行う。
ただし、１つのWebサーバーで複数のドメインのサービスを提供している可能性があるため、証明書もWebサーバー上に複数存在している可能性がある。そのため、Webサーバーがクライアントに適切な証明書を送り返すためには、クライアント側から明示的にどのFQDNにアクセスしようとしているかをサーバーに伝えなければいけない。これは`SNI(Server Name Indication)`という仕組みを使って解決され、具体的にはTLS sessionの最初のフローであるClient HelloにてServer Name(=FQDN)をクライアント側からWebサーバーに送付する。この段階ではTLS Sessionを貼るための事前作業のため、まだ暗号化されていないため、どのFQDNと接続しようとしているかは盗聴可能である。UTM装置などがHTTPSを使って暗号化されているアクセスをFQDN情報を元にフィルタリングできるのは、このSNIの情報を使っているからである。

###解決策
この問題を解決するためには、Client Helloの段階から暗号化せざるを得ない。TLS Sessionを張る前に暗号化しろというのは、ある意味鶏と卵の世界のようだが、DNSにWebサーバーの公開鍵を配置しておき、DNS問い合わせの時に一緒にその公開鍵も取ってきて暗号化することで解決可能である。これが`Encrypted SNI(ESNI)`と呼ばれている手法である。
https://blog.cloudflare.com/encrypt-that-sni-firefox-edition https://qiita.com/onokatio/items/434ce6c1d4fdcf3d07eb/


##3. TLS session（その２）

###課題
上記の問題は、例えばSNIに対応していない古いブラウザを使っていれば、そもそもSNIなんて送ることさえできなかったので、課題１には該当しないのではないか？と言われるとそのとおり。
ただし、そもそもSNIに対応しているかどうかに関わらず、TLS1.2まではサーバーからクライアントにに証明書を送り返すタイミングでは、まだ暗号化されていない。そのため、証明書の中身を見ることでも、どのFQDNにアクセスしようとしているかはわかってしまう（最近は、[１つの証明書の中でワイルドカード指定がされていたり、複数のドメインを登録してる](https://qiita.com/testnin2/items/0fb2211dffae2ffaec7a)ので、証明書の情報だけでアクセス先FQDNを特定するのは難しくなってきているが。。。）

###解決策
TLS1.3では、サーバーは証明書を暗号化してクライアントに送り返してくれる。

```txt:TLS1.2までの挙動
1. Client -> Server: Client Hello
2. Server -> Client: Server Hello（証明書がここに含まれる）
3. Client -> Server: Change Cipher Spec Change
4. Server -> Client: Change Cipher Spec Change
5. Client -> Server: 暗号化通信
```

```txt:TLS1.3での挙動
1. Client -> Server: Client Hello
2. Server -> Client: Server Hello（証明書含まれない）
3. Server -> Client: ここから暗号化通信開始：証明書を含む
- （以下略）
```
##4. 暗号化された通信をつかってコンテンツにアクセスする
HTTPSが暗号化されていて安全だと言っているのはこの部分だけであり、他の1-3については上述したとおり別途考慮が必要になる。