ykitaa.dev
15

https://example.com と打つと何が起きるか — ドメイン・DNS・証明書を一本の線でつなぐ

ブログを公開するためにドメインを取り、DNS レコードを設定し、証明書が自動で発行されるのを眺めていて、自分がこれらを分かっているつもりで説明できないことに気づきました。ドメインは「サイトの住所」、DNS は「名前を IP に変換するもの」、証明書は「HTTPS にするために要るもの」。どれも間違ってはいませんが、なぜそれが必要なのかそれぞれがどう噛み合っているのかを続けて説明できませんでした。

そこで整理したのがこの記事です。軸は一つだけ、https://example.com と打ってから画面が出るまでに誰が何をしているか。この線を最後まで引くと、ドメインも DNS も証明書も、バラバラの知識ではなく一つの流れの部品として並びます。そして後半で視点を「公開する側」に反転させると、同じ 3 つが今度は自分が用意するものとして再登場します。

なお、TLS の鍵交換アルゴリズムの中身や DNS のパケット構造までは踏み込みません。「誰が何を担当していて、なぜそれが要るのか」が説明できるようになることを目標にしています。

全体像:3 つの工程

ブラウザが https://example.com を開くとき、HTTP のリクエストが飛ぶ前に下ごしらえが 3 つあります。

sequenceDiagram
    autonumber
    participant B as ブラウザ
    participant D as DNS
    participant S as サーバー
    B->>D: example.com の住所は?
    D-->>B: 203.0.113.10
    B->>S: TCP 443 番ポートへ接続
    B->>S: ClientHello(宛先の名前 SNI + 鍵の材料)
    S-->>B: ServerHello(鍵の材料)
    rect rgba(127, 209, 166, 0.14)
        note over B,S: この枠の中は暗号化される(経路上からは読めない)
        S-->>B: Certificate(サーバーの証明書)
        S-->>B: Finished
        B->>S: Finished(証明書を検証し、鍵が確定)
        B->>S: HTTP リクエスト(中身は平文の HTTP のまま)
        S-->>B: HTTP レスポンス
    end

やっていることを言葉にすると、こうなります。

  1. 名前を引くexample.com という名前から、実際の接続先(IP アドレス)を調べる
  2. 相手を確かめる — 接続した相手が本当に example.com の持ち主か確認する
  3. 暗号で喋る — 盗み見られない鍵を決めて、以後の通信を包む

HTTPS は HTTP とは別のプロトコルではありません。HTTP そのものは何も変わっておらず、この下ごしらえを済ませた通り道の中を流れているだけです。2 と 3 をまとめて引き受けているのが TLS で、その中で証明書が使われます。

図の最後で HTTP のやり取りが暗号化の枠の中にあるのは、そのためです。HTTP は最初から最後まで平文のテキストプロトコルで、暗号化の仕事は一切していません。外側を TLS が包んでいるだけです。

ClientHello から Finished までが TLS ハンドシェイクです。順番に注目してください。鍵の材料を先に交換し、証明書はそのあと、暗号化された中で届きます(TLS 1.3 の場合)。「証明書で相手を確認してから鍵を決める」と思いがちですが、実際は逆で、鍵の合意を先に済ませ、その保護下で身元確認をしています。平文で流れるのは最初の 2 通だけです。

以降はこの 3 つを順に見ていきます。

名前を引く:ドメインと DNS

なぜ名前が要るのか

IP アドレスを直接打てば済む話に思えますが、名前が必要な理由は 3 つあります。

覚えられないことは、実は一番小さな理由です。より効くのは、IP アドレスが変わること。サーバーを引っ越しても、名前が同じなら利用者は何も知らずに済みます。そして 1 つのサービスが 1 台とは限らないこと。アクセスを複数台に分散したり、利用者に近い拠点へ案内したりできるのは、名前と実体の間に一段の変換が挟まっているからです。

名前は「住所そのもの」ではなく、住所を引くための見出しです。この間接性が、あとで証明書の話にも効いてきます。

誰がその対応表を持っているのか

DNS は巨大な分散データベースですが、「どこかに全部入りの表がある」わけではありません。example.com の答えを知っているのは、そのドメインの権威 DNS サーバーだけです。

ブラウザは直接そこへ行くのではなく、リゾルバ(プロバイダのものや 8.8.8.8 のような公開のもの)に尋ねます。リゾルバは答えを持っていなければ、ルート → .com を管理するサーバー → example.com の権威サーバー、と順に辿って答えを持ち帰り、しばらくキャッシュします。

キャッシュがあるおかげで毎回ルートから辿らずに済みますが、代わりに設定を変えてもすぐには全員に届きません。レコードに付いている TTL の間、世界中のリゾルバは古い答えを返し続けます。

最小限のレコード

では、その権威サーバーは何を返しているのか。答えの中身がレコードです。用途ごとに何種類もありますが、「名前から接続先を引く」という目的に絞れば、まずは 2 つで足ります。

A レコードは、名前から IP アドレスへの対応です(IPv6 なら AAAA)。example.com → 203.0.113.10 のように、線の終点を直接書きます。

CNAME レコードは、名前から別の名前への転送です。www.example.com → example.pages.dev のように書くと、引いた相手がさらにその名前を引きに行きます。

一見すると A のほうが素直ですが、実務では CNAME が重要です。CDN や PaaS に載せる場合、こちらに割り当てられるのは固定 IP ではなく「名前」であることがほとんどだからです。相手側が裏で IP を入れ替えても、CNAME で名前を指しておけば追従できます。A レコードで IP を直に書いてしまうと、相手の都合で切り替わった瞬間に繋がらなくなります。

ひとつ罠があって、ドメインそのもの(example.com)には CNAME を置けません。仕様上、他のレコードと共存できないためです。この制約は各社が独自に回避しており(ALIAS、ANAME、CNAME フラットニングなどと呼ばれます)、「www ありなら動くのに www なしだと設定できない」という現象の正体はこれです。

1 つの IP に複数のサイト

名前の話にはもう一つ側面があります。1 台のサーバーが複数のサイトを配信しているケースです。共有ホスティングや CDN では当たり前で、同じ IP アドレスに何千ものサイトが同居しています。

このとき、接続してきた相手がどのサイトを見たいのかは、IP アドレスだけでは判別できません。だから名前をもう一度伝えます。HTTP では Host ヘッダで、TLS では SNI(Server Name Indication)という拡張で、接続の最初に「example.com に用がある」と告げています。

SNI が重要なのは、サーバーがどの証明書を提示すべきかを、この時点で決める必要があるからです。そして SNI は、まだ鍵が何も決まっていない最初の 1 通(ClientHello)に載るので、平文で流れます。証明書そのものは暗号化された中で届くのに、宛先の名前だけは先に出さざるを得ない。「どのサイトを見ているか」が経路上から分かってしまう、というのはここに由来します。

これを塞ぐのが ECH(Encrypted Client Hello) で、2026 年 3 月に RFC 9849 として標準化されました。ClientHello ごと暗号化する仕組みで、そのための鍵は DNS 経由で配られるため、DNS over HTTPS とセットで機能します。Cloudflare のように自社ネットワーク上のドメインで既定で有効にしている事業者もあり(このブログもそれに乗っています)、「SNI は必ず平文」という前提は崩れつつあります。

名前は住所を引くためだけでなく、通信の途中でも使われているわけです。

暗号で喋る:HTTPS が守っているもの

ここまでで接続先は決まりました。次は中身の話です。

HTTPS は、先ほど書いたとおり HTTP を TLS で包んだものです。包むことで守られるのは 3 つあります。

盗聴されないこと(内容を読まれない)、改竄されないこと(途中で書き換えられたら気づける)、そしてなりすまされないこと(相手が本物だと確認できる)。

前の 2 つは暗号技術そのもので解決します。鍵を知らない第三者には読めず、鍵を知らずに書き換えれば検証に失敗します。

ところが、3 つ目だけは暗号化では解決しません。これがこの記事で一番大事な点です。

考えてみると分かります。暗号化とは「鍵を共有した相手との通信を第三者から守る」技術です。では、その鍵を共有した相手が攻撃者だったらどうなるか。通信は完璧に暗号化されたまま、攻撃者に筒抜けになります。

相手を確かめる:なぜ証明書が要るのか

暗号化されていても盗める

ここで考えるのは、証明書という仕組みがなかったら何が起きるかです。カフェの Wi-Fi に悪意のある機器がいて、DNS の応答を偽ったとします。example.com の住所を尋ねたブラウザは、攻撃者の IP を受け取ります。ブラウザは疑わずに接続し、攻撃者と鍵を交換し、暗号化された通信を始めます。攻撃者は受け取った内容を復号し、本物の example.com に中継して、返ってきた応答をまた暗号化してブラウザに返す。

flowchart LR
    B[ブラウザ] <-->|暗号化| A[攻撃者]
    A <-->|暗号化| S[本物の example.com]
    A -.- N([ここでは平文で読める])

両側とも完璧に暗号化されているのに、真ん中で全部読まれています。これが中間者攻撃です。「暗号化されているか」と「相手が本物か」は、まったく別の問題だということがここで分かります。

なお、この入口である「DNS 応答の偽装」自体を防ぐ仕組みもあります。応答に署名を付ける DNSSEC や、リゾルバとの通信を暗号化する DNS over HTTPS です。ただしどちらも「引いた答えが正しい」ことしか保証せず、接続した先が本物かどうかは別途確かめる必要があります(この記事では深入りしません)。

必要なのは、鍵を交換する前に「お前は本当に example.com なのか」を確かめる手段です。しかし相手が自分で「私は example.com です」と名乗るだけなら、攻撃者も同じことを言えます。自己申告では解決しないので、第三者に保証してもらう。それが証明書です。

証明書は何を言っているのか

サーバー証明書は、おおまかに言えば「この公開鍵は、example.com というドメイン名の持ち主のものである」という宣言に、CA(認証局)が電子署名したものです。

ブラウザは受け取った証明書について、少なくとも次を確認します。署名が正しいか名前が一致しているか(アクセスした example.com がその証明書に含まれているか)、有効期限が切れていないか

ここで当然の疑問が出ます。その CA が本物かどうかは、誰が保証するのか

信頼の連鎖

答えは「ブラウザと OS が、信頼するルート CA の一覧をあらかじめ持っている」です。

  Root CA           <- OS / ブラウザに最初から入っている
    |  署名
  Intermediate CA
    |  署名
  example.com の証明書

サーバーが提示するのは自分の証明書と中間 CA の証明書で、ブラウザはその署名を辿っていき、手元のルート証明書に行き着けば信頼するという判断をします。ルートは署名で保証されているのではなく、「最初から入っている」ことで信頼の出発点になっています。

つまり HTTPS の信用は、最終的にブラウザや OS のベンダーが誰を信じているかに帰着します。ここは技術というより制度の話で、実際、不正な証明書を発行した CA がルートストアから外される、という事件は何度も起きています。

では、その不正発行はどうやって見つかるのか。**証明書透明性(Certificate Transparency)**という仕組みがあり、発行された証明書は公開のログに記録されます。ドメインの持ち主は、自分の名前で身に覚えのない証明書が出ていないかを監視できますし、CA の排除もこの記録が根拠になります。信用の出発点が「最初から入っている」ことである以上、後から検証できる形で全部見えるようにしておく、という補強です。

証明書が証明していないこと

もう一点、誤解しやすいところがあります。証明書が保証しているのは、そのドメイン名の持ち主であることだけです。

運営会社が実在するかどうかも、そのサイトが安全かどうかも、証明書は何も言っていません。フィッシングサイトでも、自分が用意したドメインの証明書は正規に取得できます。鍵マークが意味するのは「今つないでいる相手は、確かにこのドメイン名の持ち主で、通信は暗号化されている」であって、「このサイトは信頼できる」ではありません。

(より厳格に組織の実在性まで確認する証明書も存在しますが、現在のブラウザの表示上はほとんど区別されなくなっています。)

だからこそ、発行にあたって CA が確認するのはドメインの所有権です。ここで、2 章で扱った「名前」の話と繋がります。

公開する側から見る

ここで視点を反転させます。ここまでは https://example.com訪れる側の話でした。同じ 3 つを、自分が公開する側から見ると、そのまま作業手順になります。

① ドメインを取る

まず名前が要ります。「ドメインを買う」と言いますが、正確には買っていません.com.dev といった名前空間はそれぞれレジストリが管理していて、私たちが得るのはその名前を使う権利を、期限付きで借りることです。レジストラ(お名前.com や Cloudflare Registrar など)は、その窓口にあたります。

だから毎年の更新料があり、更新を忘れれば他人が取得できる状態に戻ります。所有権ではなく使用権だ、という理解があると、この挙動が腑に落ちます。

② DNS に載せる

名前を手に入れただけでは、誰も住所を答えてくれません。その名前について答える権威サーバーを決め、そこにレコードを置く必要があります。

レジストラで設定する NS レコードが「この名前については、あのサーバーに聞いてくれ」という委任の指定です。委任先は、レジストラが提供する DNS でも、Cloudflare や Route 53 のような別のサービスでも構いません。そこに A や CNAME を置いて、初めて名前が引けるようになります。

③ 証明書を発行してもらう

次は「本物である」ことの証明です。CA に申請すると、あなたが本当にそのドメインの持ち主かを確認されます。確認方法は主に 2 つで、どちらも「持ち主にしかできないこと」をやらせる仕組みです。

HTTP 検証は、指定されたパス(/.well-known/acme-challenge/...)に指定された文字列を置かせ、CA がそれを取りに来ます。そこに置けるのはサーバーを支配している人だけ、という理屈です。

DNS 検証は、_acme-challenge.example.com のような名前に、指定された TXT レコードを置かせます。DNS に書き込めるのは名前の持ち主だけ、という理屈です。こちらはサーバーを公開する前でも使え、*.example.com のようなワイルドカード証明書にも対応できます。

この 2 つを図にすると、こうなります。

sequenceDiagram
    autonumber
    participant Me as 自分(ACME クライアント)
    participant CA as CA(Let's Encrypt など)
    participant W as DNS / Web サーバー
    Me->>CA: example.com の証明書がほしい
    CA-->>Me: ではこのトークンを置いてください
    Me->>W: TXT レコード(DNS 検証)または指定パス(HTTP 検証)に置く
    Me->>CA: 置いたので確認してください
    CA->>W: 本当に置いてあるか、外から取りに行く
    W-->>CA: 置いてある
    CA-->>Me: 所有権を確認。これが証明書です

肝は 5 番です。CA が外から取りに来るので、そのドメインの DNS やサーバーを支配している人にしか応じられません。これが「所有権の証明」の中身です。

この一連のやり取りは ACME というプロトコルで自動化されており、Let's Encrypt はこれを無料で提供しています。証明書の有効期間は短くなる一方で、Let's Encrypt は標準の有効期間を 45 日へ短縮する方針を進めているほか、6 日間しか有効でない証明書も一般提供しています。手作業での更新はもはや現実的ではなく、自動更新の仕組みを持つことが前提です。

ついでに、逆向きの仕組みにも触れておきます。CAA レコードは「このドメインに証明書を発行してよい CA はどこか」を DNS に書いておくものです。CA は発行前にこれを参照する義務があり、許可されていない CA は発行を断ります。所有権を証明して発行してもらうのが「攻め」なら、CAA は**他の CA から勝手に発行されるのを防ぐ「守り」**です。ここでも効いているのは、名前を管理する権限です。

④ サーバーに置く

最後に、発行された証明書と秘密鍵を配置します。以降、サーバーは TLS ハンドシェイクのたびにこの証明書を提示し、ブラウザが検証し、暗号化された通信が始まります。冒頭の図の (3) 以降です。

ただし置き場所は、必ずしも自分のサーバーとは限りません。CDN やロードバランサで TLS を終端する構成なら、証明書を持つのは前段です。この選択肢は後の章でまとめて扱います。

ドメインが必要な、もう一つの理由

ここまで来ると、最初に挙げた「名前が要る理由」にもう一つ追加できます。

証明書は、基本的にドメイン名に対して発行されるものだからです。

正確に言うと、IP アドレスに対する証明書も存在します。Let's Encrypt は IP アドレス証明書を一般提供していて、IPv4 でも IPv6 でも取得できます。ただし条件が厳しく、有効期間は約 6 日、所有権の確認は HTTP 系の方法に限られ(DNS 検証は使えません)、当然ながら IP が変わればやり直しです。

冒頭で「IP アドレスは変わる」と書きましたが、それがここで二重に効いてきます。名前を持たないということは、住所が変わるたびに、利用者への案内も証明書も作り直すということです。制度上できないのではなく、運用が成立しない。結局のところ、継続的に HTTPS でサービスを出したいならドメインが要るという結論は変わりません。

「覚えやすくするため」だと思っていたものが、実は信用を担保するための土台でもあった、というのが、この線を最後まで引いてみて一番の収穫でした。

何を肩代わりしてもらうか

自分でドメインを用意し、自分で証明書を管理する必要は、必ずしもありません。選択肢は「どこまで他人に任せるか」で整理できます。

ドメインをどうするか

方法 URL 向いている場面
共有ドメインに乗る(*.vercel.app*.workers.dev など) 自分のものにならない 試作、社内向け、検証環境
自分で取得する 自分のものになる 公開するサービス、長く運用するもの

共有ドメインは証明書まで込みで何も考えずに済みますが、URL が自分のものにならないのが決定的な違いです。サービスを乗り換えれば URL は変わり、それまでのリンクも検索結果も失われます。

証明書をどう手に入れるか

方法 更新 注意点
プラットフォーム任せ(PaaS のカスタムドメイン機能) 自動 そのプラットフォームの外では使えない
Let's Encrypt(ACME) 自動(自分で回す) 更新の仕組みと失敗時の監視が要る
クラウドのマネージド証明書(ACM など) 自動 そのクラウドの中でしか使えない
自己署名 自分で ブラウザが警告する。公開用途では使えない

CDN やプロキシを前段に置く構成(Cloudflare など)では、証明書は前段が持ちます。その場合、前段と自分のサーバーの間をどう保護するかは別の設定であり、ここを暗号化しないままにすると「ブラウザから見れば HTTPS だが、途中は平文」という状態になります。鍵マークが付いているからといって、経路全体が保護されているとは限りません。

このブログの場合

最後に、実際にやったことを書いておきます。このブログ(ykitaa.dev)は次の構成です。

ドメインは Cloudflare Registrar で取得しました。ここは卸値のまま販売する方針なので、.dev は年 12.20 ドル(2026 年 9 月時点)で、更新時に値上がりしません。

.dev を選んだことには副作用もあります。この TLD は HSTS preload リストに登録済みで、ブラウザは .dev のドメインに対して最初から HTTPS でしか接続しません。http:// と打っても平文のリクエストは飛びません。ドメインの選択が、そのまま HTTPS の強制に直結するわけです。

DNS と証明書は、自分では何もしていません。Cloudflare Workers にサイトを載せ、管理画面でカスタムドメインとして ykitaa.dev を追加しただけです。ドメインとホスティングが同じアカウントにあるので、必要な DNS レコードは自動で作られ、証明書も自動で発行・更新されます。

つまり、この記事で書いた ②DNS と ③証明書の手続きを、まるごと肩代わりしてもらっています。省けたのは、権威 DNS の管理、ACME クライアントの設置と運用、そして更新失敗の監視です。最後のものが地味に大きく、証明書の有効期間が短くなっている現在、自前で回すなら「更新が止まっていることに期限切れまで気づかない」事故をどう防ぐかまで考える必要があります。

実際にどうなっているかは、外から確認できます。証明書は Google Trust Services から出ていて、中間 CA を挟んでルートに繋がっています。

$ openssl s_client -connect ykitaa.dev:443 -servername ykitaa.dev
  Protocol : TLSv1.3
  0 s:/CN=ykitaa.dev
  1 s:/C=US/O=Google Trust Services/CN=WE1
  2 s:/C=US/O=Google Trust Services LLC/CN=GTS Root R4

CAA レコードも設定されています。自分では 1 行も書いていませんが、発行してよい CA が DNS 上で宣言されている状態です。

$ dig +short CAA ykitaa.dev
  0 issuewild "pki.goog; cansignhttpexchanges=yes"
  0 issuewild "ssl.com"
  0 iodef "mailto:tls-abuse@cloudflare.com"

代わりに預けたものもあります。ドメイン・DNS・証明書・配信がすべて 1 社に集中しているので、移行するときはまとめて動かすことになります。個人ブログであれば、手間が消えることのほうが価値が大きいと判断しました。

おわりに

整理してみると、3 つはこういう関係でした。

ドメインは、レジストリから期限付きで借りている名前です。DNS は、その名前を実際の接続先に変換する仕組みで、権威サーバーが答え、リゾルバがキャッシュします。証明書は、「この鍵はその名前の持ち主のものだ」と第三者が署名したもので、暗号化では解決できない「なりすまし」を防ぎます。

そして 3 つは、名前という一点で繋がっています。名前があるから住所を引ける(DNS)。名前の持ち主であることを証明できるから、信用が成立する(証明書)。冒頭で「ドメインはサイトの住所」と思っていたのは半分で、残り半分は信用の宛先でした。

ブラウザのアドレスバーにある鍵マークが言っているのは、結局この一文だけです。「今つないでいる相手は、確かにこのドメイン名の持ち主です」。それ以上でも以下でもない、と分かったことが、今回いちばんすっきりした点でした。