それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

DoH:DNS-over-HTTPS なサーバーを作って試す。

DoH サーバーを作って問い合わせをちょっとだけ秘密にする。

DNS によるブロッックングが2019 上半期の一番の話題だったと思う。DNSブロッキングはUKで実際に運用されていたり、法制度化されているので本邦でも導入するべきと言った論調だった。児童ポルノでも一定の成果を上げているしーみたいな?まぁお手本にしたUKや中共ではプライバシー保護の議論は常にあるし、我が国も早晩、プライバシー保護と監視の両立を迫られることになる。その際にブラウザがDoHで問い合わせを保護する方法は重要に担ってくると思う。

DoH DNS over HTTPS を体験してみる

DoH を体験しておけば、問題点や課題が少しでもわかるのではないでしょうか。そうおもって使ってみることにしました。

DoH なサーバーを作る

DoH は中間にめっちゃいろいろ挟まるので、最初に概要だけ書いておきます。

dns-https クライアント → Webサーバー(ssl処理) → dohプロキシ → unbound(DNS問合せ)

DoH プロキシは 今回、python のpip で導入します、多種実装があります。

ブラウザ→WEBサーバのSSLはLetsEnctyptで導入されているものとします。*1

DoHプロキシの準備

インストール先を作って pipenv 環境を整える

target=/var/www/virtualhosts/dns.example.com/doh
mkdir -p   $target
cd  $target
pipenv install 
pipenv run pip install pip --upgrade
pipenv run pip install doh-proxy

pipenv は導入されているものとします。

doh を起動します。

pipenv run doh-httpproxy --level DEBUG \
  --upstream-resolver 192.168.1.1 \
  --listen-address=127.0.0.1 \
  --trusted=127.0.0.1 \
  --port 8053

ここでは、DoH プロキシを起動しています。

--upstream-resolver 192.168.1.1 では、DoHプロキシがDNSの実レコードを問い合わせるリゾルバを指定(ルータとか unbound とか ISP DNSとか public DNSとか)

--listen-address=127.0.0.1 --trusted=127.0.0.1 --port 8053 では、DoHがリッスンするIP/ポート。さらに信頼するHTTP中間プロキシのIPを記述

https する nginx の設定例

httpsTLS通信を nginx に任せることにするので、該当のWEBサーバの記述を作ります。

nginx ではSNIでドメイン名を受け取り、それを先程のDoHサーバーに転送します。

# vim: ft=nginx ts=2 sw=2 sts=2

server {

  server_name  dns.example.com;

  add_header  X-Robots-Tag "noindex, nofollow, nosnippet, noarchive";

  listen 443 ssl http2;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

  if ($scheme = http) {
    return 301 https://$server_name$request_uri;
  }


  location /dns-query {
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_redirect off;
    proxy_buffering off;
    proxy_pass http://127.0.0.1:8053;
  }
}

設定ができたら、リロード再起動

sudo nginx -t && sudo service nginx reload

最後に接続確認

nginx とdoh-プロキシの準備と起動すべてが終わったら。接続してみる

pyenv run doh-client --domain dns.example.biz --qname t.co --qtype a

応答例

2019-07-16 15:10:13,417:    DEBUG: Opening connection to dns.example.biz
2019-07-16 15:10:13,423:    DEBUG: Query parameters: {'dns': 'AAABAAABAAAAAAAAAXQCY28AAAEAAQ'}
2019-07-16 15:10:13,424:    DEBUG: Stream ID: 1 / Total streams: 0
2019-07-16 15:10:13,428:    DEBUG: Response headers: [(':status', '200'), ('server', 'nginx/1.10.3'), ('date', 'Tue, 16 Jul 2019 06:10:13 GMT'), ('content-type', 'application/dns-message'), ('content-length', '293'), ('cache-control', 'max-age=378'), ('x-robots-tag', 'noindex, nofollow, nosnippet, noarchive')]
id 0
opcode QUERY
rcode NOERROR
flags QR RD RA
;QUESTION
t.co. IN A
;ANSWER
t.co. 378 IN A 104.244.42.133
t.co. 378 IN A 104.244.42.5
t.co. 378 IN A 104.244.42.69
t.co. 378 IN A 104.244.42.197
;AUTHORITY
t.co. 12577 IN NS ns1.p34.dynect.net.
t.co. 12577 IN NS ns2.p34.dynect.net.
t.co. 12577 IN NS d01-02.ns.twtrdns.net.
t.co. 12577 IN NS c.r06.twtrdns.net.
t.co. 12577 IN NS ns3.p34.dynect.net.
t.co. 12577 IN NS a.r06.twtrdns.net.
t.co. 12577 IN NS b.r06.twtrdns.net.
t.co. 12577 IN NS ns4.p34.dynect.net.
t.co. 12577 IN NS d01-01.ns.twtrdns.net.
t.co. 12577 IN NS d.r06.twtrdns.net.
;ADDITIONAL
2019-07-16 15:10:13,432:    DEBUG: Response trailers: {}

サーバーのログの例

curl 単体接続で見れないの?

専用クライアントを経由して見てますが、curl で問い合わせるには、hexdump して base64エンコードしないとダメなので、そのままでは見られなかった。

curllocalhost:8053 でdoh-proxy と直接通信する例。

 echo -n 'q80BAAABAAAAAAAAA3d3dwZnb29nbGUDY29tAAABAAE=' | base64 -d \
\
 | curl -s -H 'content-type: application/dns-message' \
 'http://localhost:8053/dns-query' \
  -H 'X-Forwarded-For: 127.0.0.1'\
  --data-binary @-| hexdump -C \

ハッキリ言ってめんどくさい。

https://www.secjuice.com/modsecurity-web-application-firewall-dns-over-https/

Firefoxで使ってみる

手早く試すには、Firefox でDoHサーバーを使うのが良いと思います。

わかったこと

443ポートでSNIするから、ポート53が必要なくなる。通常のWEBと同じくHTTPSドメイン名で待ち受ける事ができるので便利。443の用途がまた増えてしまった。

HTTPSをするので改竄やオレオレが難しい。クライアントは安全になる。

DoHプロキシとUnboundの通信は暗号化されないし丸見えで従来どおり。全く今までどおり。

対応クライアントがFirefoxくらいしか無い。iOSが対応したら嬉しいな.

ただし、nginx で待ち受けてるDNSホスト名の名前解決には、従来どおりのDNSが必要。ここで詐称される可能性はあるがHTTPSで改ざん検出は可能かもしれない。しかし証明書の確認のためにCRL引っ張りに行くのもまたDNSが・・・ああエンドレスリピートは変わらない。

一般市民が、public DNS経由でブラウザを使うだけならかなり安全になるかと思う。

2023-06-05

記述ミスを修正

参考資料

https://facebookexperimental.github.io/doh-proxy/tutorials/nginx-dohhttpproxy-unbound-centos7.html

*1:めんどくさければCloudfrontとかのhttpsCDN挟んでください。