rainydrate

torabit.dev の HTTPS only と Domain Protection

2026年10月18日

Intro

torabit.dev を IPv6 only で公開した では、IPv4 を断る仕組みを書いた。 この記事では、IPv4 か IPv6 かに関係なく torabit.dev に入れている設定を書く。 平文の HTTP で中身を返さないことと、ドメインを他人に悪用させないことの 2 つだ。

この記事に出てくるレコードを、先に一覧にしておく。

レコード中身torabit.dev での使い方
TXT任意の文字列。所有の証明やメールの設定に使うGitHub の所有確認、SPF、DMARC
MXメールの受け取り先受け取らないと宣言する
CAA証明書を発行してよい CALet’s Encrypt だけ
HTTPSHTTPS で接続するためのヒントHTTP/2 と IPv6 アドレスを告知する
DS子のゾーンの署名鍵のハッシュを、親のゾーンに登録したもの.dev に登録されている

HTTPS only

torabit.dev は、平文の HTTP では中身を返さない。 ただし :80 を閉じてはいないので、厳密には HTTP を断っていない。 平文で返すのはリダイレクトだけで、ブラウザがそこに来ることもない。 そのための仕組みを 3 段重ねている。

1 段目は GitHub Pages の Enforce HTTPS だ。 これを有効にすると、http:// で来た接続には 301 で https:// を返す。

$ curl -6 -sS -o /dev/null -w '%{http_code} %{redirect_url}\n' http://torabit.dev/
301 https://torabit.dev/

この 301 自体は平文で返る。 平文の HTTP では、リクエストのパスやヘッダーが経路上からそのまま読める。 レスポンスも読めるうえに書き換えられるので、経路上の攻撃者は 301 を偽のページに差し替えることもできる。

それなら、:80 を閉じて平文の接続そのものを受けなければよい、と最初は考えた。 しかし、:80 を閉じて守れる相手は限られる。 カフェの Wi-Fi で誰かが通信を狙っている場面で考えると、相手は 2 種類いる。

1 つ目は、同じ Wi-Fi にパケットキャプチャのツールをつなぎ、流れてくる通信を記録しているだけの相手だ。 中身は読めるが、書き換えたり、代わりに返事をしたりはできない。 この相手なら、:80 を閉じる効果はある。 サーバが応じないので、ブラウザはパスやヘッダーを送る前に接続を終え、見られる中身もない。

2 つ目は、カフェのアクセスポイントを偽物にすり替えるなどして、通信の通り道に入り込んでいる相手だ。 この相手は通信を途中で受け止めて、好きな返事を返せる。 ブラウザが :80 に接続しようとすると、本物のサーバに届く前に、この相手が torabit.dev のふりをして応じてしまう。 本物のサーバが :80 を閉じていても、ブラウザにはそれを知る方法がない。 平文の HTTP には、相手が本物かを確かめる仕組みがないからだ。

つまり :80 を閉じても、守れるのは 1 つ目の相手だけだ。

そもそも GitHub Pages では :80 を閉じられない。 閉じられるのは自分でサーバを持つ場合だけで、試した範囲では Cloudflare も Netlify も Vercel も、:80 で受けてリダイレクトを返していた。 証明書を取るための確認も :80 に来るので1、Let’s Encrypt も Best Practice - Keep Port 80 Open で :80 を開けておくよう勧めている。

仮に閉じられたとしても、割に合わない。 1 つ目の相手に覗かれるのは最初の 1 回のリクエストの URL とヘッダーくらいで、Cookie も Secure 属性を付けておけば平文には乗らない。 それより、http:// で来た人をエラーにする損の方が大きい。

2 つ目の相手から守るには、ブラウザが最初から https:// で接続するようにするしかない。 それをするのが 2 段目の、.dev という TLD 自体の仕掛けだ。 .dev は TLD 全体が HSTS preload リストに入っている。 HSTS は「このドメインには HTTPS でしか接続しない」とブラウザに覚えさせる仕組みで、preload はそれをブラウザに最初から組み込んでおくものだ。 そのため http://torabit.dev/ と打っても、ブラウザは :80 に接続する前に HTTPS に書き換える。 1 段目の 301 が効くのは、curl のようなブラウザ以外のクライアントだけになる。

HSTS は普通、サーバが Strict-Transport-Security ヘッダーを返して、ブラウザに覚えさせる。 自分のドメインを preload リストに登録するのにも、このヘッダーが要る。 しかし、GitHub Pages はこのヘッダーを返さない。

$ curl -6 -sSI https://torabit.dev/ | grep -i -E '^HTTP|strict-transport|server'
HTTP/2 200
server: GitHub.com

つまり GitHub Pages で配信する限り、HSTS を使えるのは .dev や .app のように TLD ごと preload されている場合だけだ。 TLD を選んだ時点で、HTTPS only の設計が決まっていた。

3 段目は HTTPS RR だ。

$ dig +short HTTPS torabit.dev
1 . alpn="h2" ipv6hint=2606:50c0:8000::153,2606:50c0:8001::153,2606:50c0:8002::153,2606:50c0:8003::153

HTTPS RR は、接続する前に DNS の段階で「HTTPS で、このプロトコルで、このアドレスに来い」と告知するレコードだ。 Cloudflare の DNS に、自分で 1 本書いた。 対応したブラウザは、このレコードがあるだけで最初から HTTPS で接続する。 ただ、手元の Chrome はこのレコードを使っていない。 この件は別の記事で書く。

出力の読み方は次のとおりだ。

  • 1:優先度。HTTPS レコードが複数あるとき、クライアントは数字の小さいものから順に試す。0 だけは特別で、別名の指定になる2。torabit.dev は 1 本しかないので、順番としては働かない
  • .:接続先の名前。. は「この名前自身(torabit.dev)に接続せよ」という意味
  • alpn="h2":HTTP/2 に対応している
  • ipv6hint=...:接続先の IPv6 アドレスのヒント。AAAA レコードの応答を待たずに接続を始められる。AAAA レコードの応答が届けば、そちらが優先される

GitHub Pages の応答には HTTP/3 対応を知らせる alt-svc ヘッダーがないので、alpn に h3 は書いていない。 HTTPS への引き上げは HSTS preload で既に効いているので、HTTPS RR の効果はそれと重複する。 それでも実験として置いている。

Domain Protection

ドメインを持つと、自分が使っていない場面でも torabit.dev は悪用されうる。

  • メールの送信元として名乗られる
  • 自分の知らないところで証明書を取られる
  • 他人の GitHub Pages に torabit.dev を紐付けられる
  • DNS の応答そのものを偽られる

どれも、torabit.dev 側が何もしていなくても起きる。 メールについては、Cloudflare のダッシュボードに実際になりすましの警告が出ていた。 そこで、上の 4 つを順に締めておいた。

まずはメールだ。 メールを使わないドメインでも、受け取る側がなりすましを判断できるよう、「このドメインはメールを送受信しない」と宣言しておく。

レコード値意味
TXT(SPF)v=spf1 -allこのドメインから正当に送るサーバはない
TXT(DMARC、_dmarc)v=DMARC1; p=reject;認証に失敗したメールは拒否してよい
MX0 .メールを受け取らない(Null MX)

次に証明書だ。

対策中身
CAA0 issue "letsencrypt.org"。Let’s Encrypt 以外の CA は torabit.dev の証明書を発行できない
CT 監視ブラウザは Certificate Transparency ログに記録されていない証明書を信頼しないので、発行された証明書は実質すべてここに載る。Cloudflare の Certificate Transparency Monitoringを有効にして、発行されたらメールが届くようにした

GitHub の verified domain も登録した。 TXT レコードで torabit.dev の持ち主であることを GitHub に示しておくと、他人のリポジトリが torabit.dev を名乗れなくなる。

最後に DNSSEC を有効にした。 DNSSEC は DNS の応答に署名を付け、ルートから .dev、torabit.dev へと署名の連鎖をたどって改ざんを検知できるようにする仕組みだ。 Cloudflare で有効にすると、Registrar も Cloudflare なので .dev への DS レコードの登録まで自動で進む。

$ dig +short DS torabit.dev @ns-tld1.charlestonroadregistry.com
2371 13 2 2ACB947BAABC1A34CB577777C857DE9A091780B6D8651909164D8685 19654292
$ delv @8.8.8.8 AAAA torabit.dev | head -1
; fully validated

Outro

HTTPS only の大半は .dev が TLD ごと引き受けていて、自分で足したのは Enforce HTTPS と HTTPS RR だけだった。 Domain Protection の 4 つも、レコードを書くか設定を有効にするだけで済んだ。 どちらも IPv6 only とは関係なく入れられるので、ドメインを取ったら最初に済ませておきたい。

Footnotes

  1. GitHub Pages は Let’s Encrypt の HTTP で確かめる方式を使っている模様で、その確認は :80 に来る。詳しくは torabit.dev を IPv6 only で公開した の Certificate の節に書いた。 ↩

  2. 優先度 0 の HTTPS レコードは、CNAME と同じように「この名前の HTTPS の情報は、別の名前のものを使え」と指定する。たとえば torabit.dev. HTTPS 0 torabit.github.io. と書く。CNAME と違って zone apex にも置けるので、zone apex に別名を書けない問題を解く手段の一つになる。ただし、2025 年 12 月時点の調査では、別名をたどるのは Safari だけで、Chrome と Firefox は対応していない。 ↩