🔍

「URLを誰にも教えてない」が通じない理由 — CTログを30分監視してみた

に公開
2

独自ドメインを取ってWebサイト/アプリを公開するとき、「URL(ドメイン)を誰にも教えていないから大丈夫」と油断していませんか?

結論から言うと、これは成り立ちません。

独自ドメインを取って HTTPS の証明書を発行すると、その時点でドメイン名は CT(Certificate Transparency)ログという公開ログに記録されます。
このログを監視しているbotは大量に存在していて、新しく現れたドメインに対して自動でアクセスを試みています。

実際にどんな景色になっているのか気になったので、CTログを30分間監視して、新規ドメインを観測してみました。

倫理・法律の境界線を守りながら、外から見える範囲だけで観測した結果です。

TL;DR

  • 30分のCTログ監視で 88,450件 の証明書発行イベント、その中から直近2日以内に登録された個人/小規模ドメイン 62件を抽出
  • そのうち、実際にアプリが動いていたサイトは7件(11%)だけ。残りの大半は「ドメインを取っただけ」か「マーケットプレイスの在庫」
  • 動いていた7件はほぼ全て AI系SaaSのアイデア × Cloudflare/Vercel という景色
  • セキュリティヘッダはほぼ全滅。X-Frame-Options と Permissions-Policy は 7/7 で未設定
  • 個人開発に紛れて、怪しい(ギャンブル系・ロシア語/トルコ語スパム系)ドメインも等しく出現
  • "URLを言ってない" は何の防御にもならない

CTログとは(最小限の説明)

CT(Certificate Transparency)は、HTTPS証明書の発行を透明化するための仕組みです。RFC 6962で標準化されていて、主要なブラウザは「CTログに記録された証明書しか信頼しない」というポリシーで運用されています。

つまり、

  • 独自ドメインを取って HTTPS 化する(Let's Encryptなどで証明書を発行する)
  • → その時点で世界中のCTログに「このドメインに証明書が出ました」と記録される
  • → 誰でもそのログを読める

ということです。CTログを運用しているのは Google、Cloudflare、Let's Encrypt、DigiCertなどで、HTTP APIで誰でも参照できます。

そして、このCTログを リアルタイムで監視している攻撃者は実在します。新規ドメインがログに現れた瞬間に、片っ端から https://そのドメイン/ を叩いて、何が動いているか・脆弱なエンドポイントが露出していないかを確認する、というbotがそこらじゅうにいます。

実際、独自ドメインでWebアプリを公開した直後から、/.env/wp-admin/phpmyadmin といったパスを舐めるリクエストや、../../etc/passwd 系のディレクトリトラバーサルを試みるリクエストが、アクセスログに記録され始めるというのはWeb開発者にとってはよくある光景です。URLを誰にも教えていなくても、公開直後の "誰も知らないはず" のWebアプリに対して、こうしたbotアクセスはあっという間に飛んできます。これらの送信元の多くはCTログを監視しているスキャナで、ログに新しいドメインが現れた瞬間に既知の脆弱パスを総当たりで試している、というのが正体です。

何をやったか(方法論)

やったこと

  1. CTログをポーリングしてリアルタイムに新規証明書を取得(30分)
  2. apex(登録可能ドメイン)を抽出し、商用SaaSの共有サブドメイン(vercel.app, pages.dev, herokuapp.com など)を除外
  3. ウィンドウ内で1回しか出現しなかった apex に絞る(既存サービスのサブドメイン乱発を除外)
  4. 個人開発で使われやすいTLD(.dev .app .me .io .xyz .ai .co .online .cloud など)で絞る
  5. WHOIS で creation_date が直近2日以内 のものを「本当に新規」として抽出
  6. 各ドメインに対して GET / を1回だけ叩いて、レスポンスヘッダ・TLS設定・HTMLの先頭部分を観測

やっていないこと(倫理境界)

ここは大事なところです。

やった やってない
GET /(普通のブラウザが1回トップを開くのと同じ) 認証突破の試行
HTTPレスポンスヘッダの取得 既知脆弱パスの探索(/.env, /.git, /admin 等)
TLS設定の確認(バージョン、暗号スイート) パスの総当たり
HTML先頭の取得(フレームワーク判定用) フォーム投入
DNS解決(IP取得) nikto/nmap/sqlmap 等のスキャナ

日本では不正アクセス禁止法があるので、「外部から見て、普通のアクセスで返ってくる情報」以上に踏み込まないラインを守りました。これは securityheaders.comSSL Labs が公開でやっている観測と本質的に同じ範囲です。

User-Agent も Mozilla/5.0 (compatible; ct-research/0.1) のようにbotであることを明示しています。

数字のじょうご

30分間のCTログ監視の結果を、フィルタごとにじょうごで見てみます。

88,450  証明書発行イベント(30分間)
↓ --- apex抽出 + 商用SaaSサブドメイン除外
↓ --- 1回出現 + 個人系TLD + ノイズ(hex16文字以上)除外
685  候補ドメイン
↓ --- WHOIS で creation_date が直近2日以内
62 本当に新規のドメイン
↓ --- GET / して観測
7  実際にアプリが動いていた

CTログ観測のじょうご:88,450件の証明書イベントから、最終的に7件の動作中アプリにたどり着くまで

5分の試行から始めて、母集団を確認しながら30分に伸ばしました。それでも「直近2日に新規登録された個人開発っぽいドメイン」は62件しか拾えませんでした。30分間で世界中で新規登録される個人系ドメインは、おそらく数百件のオーダーで、CTログには毎秒数百件の証明書発行イベントが流れていることになります。

発見1:今回観測した母集団では、81%が「まだ中身がない」

今回の母集団(直近2日以内に新規登録された個人開発系TLDのドメイン)62件のうち、実際にアプリが動いていたのは7件(11%)だけでした。

分類 件数 割合
empty_or_tiny(中身がない/小さすぎる) 50 81%
has_app(実アプリが動いている) 7 11%
unknown(HTMLは返るが分類しきれず) 4 6%
unreachable_https(HTTPSが繋がらない) 1 2%

empty_or_tiny の50件のうち「20件がぴったり同じIP(76.223.54.146)」にいて、しかも返してくるHTMLが全部同一でした。

<!DOCTYPE html><html><head>
<script>window.onload=function(){window.location.href="/lander"}</script>
</head></html>

これはAWS上にホストされたドメインマーケットプレイスの「売り出し中」ページのリダイレクトでした。/lander に飛ばされて「このドメイン買いませんか」というUIが出ます。

つまり、今回観測した範囲では、新規ドメインのかなりの割合が「個人が買って使い始めたドメイン」ではなく、「マーケットプレイスが転売用に確保している在庫」だった、ということです。

残りの empty_or_tiny も、レジストラ(Namecheap, GoDaddy, Hostinger など)のデフォルト「準備中」ページや、ホスティングサービスの未デプロイ状態でした。

あるあるですが、「ドメインを取ったぞ!」の瞬間と、「サイトを公開したぞ!」の瞬間には、けっこうな時間差があります

CTログには「準備中」の瞬間が大量に記録されている、という発見です。

発見2:動いてる7件、ほぼ全てAI SaaS × フルマネージド

has_app に分類された7件のホスト・フレームワーク内訳は以下のようになっていました。

ホスト 件数
Cloudflare(Pages/Workers) 5
Vercel 1
LiteSpeed(共用ホスティング) 1

動作中アプリ7件のホスティング分布:Cloudflare 71%、Vercel 14%、LiteSpeed 14%

85%(6/7)が Cloudflare/Vercel で、エッジ・フルマネージド系の独壇場でした。

そして中身は、ほぼ全てがAI関連のSaaSアイデアのランディングページや初期プロダクトでした。

  • AI ファイルQA系
  • AI 営業アシスタント系(フランス語UI)
  • AI 広告ツール系
  • AI オートメーション業務系
  • AI シグナル/分析系

唯一の例外はオーストラリアの訪問看護会社の小規模コーポレートサイト(LiteSpeed + WordPress + Rank Math)でした。

今回観測した「新規ドメインで個人が立ち上げてる何か」の景色は、ほぼ「AI × ナニカ」 × Cloudflare/Vercel だった。

そして全部、Tailwind CDN や Next.js のテンプレ感が強くて、AIにアプリを作らせて公開しているような雰囲気の構成です。AI時代の個人開発の景色が、CTログを通してリアルに観測できました。

発見3:怪しいドメインも紛れて等しく出てくる

62件の中には、マルウェア/フィッシング/ギャンブルスパム系と思しきドメインも混ざっていました(念のためマスキングしています)

  • トルコ語の rad***giris.xyz("giris" はトルコ語で「ログイン」、bet系の窓口に見える)
  • トルコ語の de***lisans.xyz("lisans" は「ライセンス」)
  • ロシア語の strannik****.xyz("strannik" は「放浪者」)
  • ランダム数字系の 901***.xyz, tx333***.xyz, wk62****.lol (マスキング部分含めてランダムに近い英数字)

これらも全部、上記の「マーケットプレイス駐車場」と同じ /lander パターンに飛ばされていました。証明書はすでに発行されている = いつでも本物のサイトに切り替えられる準備ができている、ということ。

CTログには、個人の純粋な開発も、悪意ある仕込みも、等しく現れます。
攻撃者がCTログを監視しているのは、こういう「いずれ立ち上がるサイト」を早期に把握するためでもあります。

発見4:実アプリ7件のセキュリティヘッダはほぼ全滅

実際に動いている7件だけに絞っても、セキュリティヘッダは惨憺たる状況でした。

ヘッダ 未設定
X-Frame-Options 7/7 (100%)
Permissions-Policy 7/7 (100%)
Content-Security-Policy 6/7 (86%)
Referrer-Policy 6/7 (86%)
X-Content-Type-Options 5/7 (71%)
Strict-Transport-Security 4/7 (57%)

HSTSがついている3件も、いずれもCloudflare経由で「ホスト側で設定をONにすれば自動で付与される」もの。自分でWebアプリ側に設定を書いている形跡は、ほぼ見えませんでした。

つまり、全部素のままで公開しているに等しいわけです。
AIに任せて公開すると、こういうのは「言われないとやらない」ので、こうなるのは自然かなと思います。

つまり、何が起きているのか

整理すると、今回の観測から見えてきたものは次の通りです。

  • ドメインを取った瞬間サイトを公開した瞬間
    • CTログは前者を拾うので、今回の母集団では新規ドメインの大半はまだ中身のない状態だった
  • 今回観測した範囲では、実際に立ち上がっていたサイトは、ほぼAIツール系のSaaSアイデア
    • Cloudflare/Vercelに乗っていて、ホストのデフォルト以外の防御は入っていない
  • 悪意あるドメインも同じタイミング・同じ仕組みで観測された
    • 攻撃者にとってCTログは "新規の標的リスト" として機能している
  • CTログを監視する側からすれば、新規ドメインに GET / を1回叩いて中身を判定するだけで、誰が・どこに・何を建てているか、ほぼリアルタイムに把握できる

そして重要なのは、「URLを誰にも教えてない」は何の防御にもならない、ということです。

証明書を発行した瞬間に、世界中のCTログに記録されて、世界中のbotがアクセスを試みてきます。これは Let's Encrypt を使おうが、有料CAを使おうが、回避不可能(証明書を出さない=HTTPSにしない、しかない)です。

これが個人開発者にとって何を意味するか

よくあるパターンとして、「自分専用のつもりだけど、出先からも触りたいからWebに置いた」とか「立ち上げたばっかりでとりあえずサイトを開けるようにした」みたいなケースがあります。これは、想像以上に簡単に攻撃者に観測されています。URLを誰にも言わなくても、HTTPS化した瞬間にCTログに記録されて、新規ドメインを舐めているbotから GET / を叩かれます。

なので、Webに置く(しかもHTTPS化する)のであれば、以下のどれかを必ず通すのが現実的です。

  • Cloudflare Access / Tailscale / VPN
    • 経路レベルで、自分(やチーム)以外のアクセスを物理的に弾く
  • ベーシック認証 or ログイン機能
    • トップページに到達した時点で認証を要求する

守り側として何をすればいいか

公開する側として、最低限

  • ホスティングはフルマネージドを選ぶ(Cloudflare Pages, Vercel, Netlifyなど)
    • ホスト側でHSTSなどをONにできる
  • 不要なエンドポイントを公開しない
    • .env, .git, バックアップファイル、デバッグページ
  • デフォルトクレデンシャルのまま公開しない
    • admin/admin、root/root
  • 管理画面に到達できる範囲を絞る
    • 社内向けなら Cloudflare Access、知り合い向けならベーシック認証で十分
  • 「自分専用」を本気で守りたいなら経路ごと閉じる
    • Tailscale や Cloudflare Access を使う

逆に言うと、AIにアプリを作らせてWebに公開する場合

「これって攻撃者から見えてるよね」

を前提に頼むだけで、AIの仕事は大きく変わります。「Cloudflareにデプロイして」だけでなく「Cloudflare Accessでログインを要求して」と言えば、AIはちゃんとやってくれます。

まとめ

CTログを30分監視してわかったのは、

  • 今回観測した「直近2日以内に登録された個人開発系TLDのドメイン」62件のうち、81%はまだ中身のない状態だった(うち少なくない数はマーケットプレイスの転売在庫)
  • 動いていた11%は、ほぼAI SaaS × Cloudflare/Vercel
  • 防御はホストのデフォルト止まりで、CSP・XFO・Permissions-Policyはほぼ未設定
  • 同じ仕組みで悪意あるドメインも観測される
  • 攻撃者は新規ドメインを GET / で舐めている

ということでした。あくまで今回の母集団・観測条件のもとでの結果で、TLDのフィルタや観測時間帯を変えれば分布も変わるはずですが、傾向としての示唆は読み取れます。

個人開発でWebに置くときに持っておきたい原則として、

HTTPS化した瞬間、それはもう "誰にも教えていない" ではない

これだけは覚えておいてもらえると、Webに置くときの判断が一段慎重になるはずです。


付録:今回使ったツール

  • CTログポーリング:Cloudflare Nimbus 2026(https://ct.cloudflare.com/logs/nimbus2026/ct/v1)にHTTPポーリング
  • 証明書のパースcryptography パッケージ(RFC 6962のMerkleTreeLeafを手動でパース)
  • apex抽出tldextract
  • WHOISpython-whois(直近の creation_date 取得)
  • 観測requestsGET / を1回だけ、ssl でTLSバージョン/cipher確認

なお、今回作成したスクリプトそのものは公開しません。生成AIに頼めば簡単に再現できる程度のものなので公開してもさほど意味がない一方、見方によっては攻撃の初手につながる手順でもあるためです。倫理境界(やったこと/やっていないこと)は本文に明示した通りで、観測範囲はすべて公開情報の範囲内です。

Discussion

horie-thorie-t

「URL」ではなく「ドメインを誰にも教えてない」のような…

所謂、共有リンクの危険性の話かと思ってしまった。

5
tokiyatokiya

ありがとうございます!
証明書はドメインに対して発行されるものなので厳密にはおっしゃる通りです。
「ドメイン」と書くと読者に届きにくいかなと思って敢えて「URL」にしたのですが、共有リンクの話と読めてしまうのは盲点でした。
冒頭に「独自ドメインを取って公開したとき」と一言追加しておきます、ご指摘感謝です!