つかったこのサイトについて

本番URLを推測で書いたら、実在する他人のサイトだった

デプロイ手順書を書いているときにやりました。

本番URLを書く欄に、プロジェクト名から推測した *.vercel.app のURLを「記入例」として書きました。デプロイ前だったので、まだ実際のURLを知らなかったからです。

そのURLは、まったく無関係の実在するサービスのものでした。

何が起きたか

手順書に書いた「記入例」が、そのまま環境変数に貼られました。

貼られた先が悪かった。認証ライブラリが「自分自身のURL」として使う変数です。NextAuth の AUTH_URL にあたるものだと思ってください。この変数は、OAuth のコールバック先を組み立てるのに使われます。

つまり構図はこうです。

  1. ユーザーがログインボタンを押す
  2. アプリが Google へ「認証が終わったら この URL に戻してくれ」と伝える
  3. その「この URL」が、他人のドメインになっている

ログインは動きませんでした。動かなくてよかったというのが正直な感想です。

「動かなかった」で済んだ理由

OAuth のリダイレクト先は、プロバイダ側の許可リストと一致しないと弾かれます。Google Cloud の OAuth クライアントに登録した「承認済みのリダイレクトURI」に他人のドメインは入っていないので、認証はエラーで止まります。

この許可リストが最後の砦として機能しました。

裏を返すと、砦がそこしかなかったということでもあります。もし許可リストにワイルドカードを使っていたり、リダイレクト先の検証が緩い実装だったりすれば、認可コードが他人のサーバへ送られる構図でした。

*.vercel.app は共有の名前空間

ここが今回の学びの核心です。

*.vercel.app のサブドメインは、Vercel 全体で共通の、先着順の名前空間です。自分のプロジェクトに notebook という名前を付けたからといって、notebook.vercel.app が自分のものになるわけではありません。

そして、名前が空いているとは限りません。 短くて一般的な単語なら、まず埋まっています。

自分のプロジェクトに割り当てられる実際のURLは、Vercel の管理画面に表示されているものだけです。それ以外は他人のものです。

やったこと

1. 実際のURLを管理画面からコピーして設定し直した

推測をやめる。これだけです。

2. 手順書から「記入例」のURLを消した

いま手順書はこう書いてあります。

🔴 記入例をそのまま貼らないこと。実在する他人のサイトへ認可コードが飛ぶ。

例として書いたURLは、例として読まれません。 手順書は、急いでいる人が上から順に埋めていくために存在します。「例」という但し書きは、そういう読まれ方をしません。

書くならプレースホルダにします。https://<Vercelの管理画面に表示されているURL> のように、そのまま貼ると明らかに壊れる形にする。

3. そもそもこの変数を消した

別のプロジェクトでは、この手の「自分自身のURL」変数を環境変数から外しました。コード側に既定値を持たせて、環境変数がなくても正しいURLになるようにしています。

// 環境変数が未設定でも、本番のURLになる
export const site = {
  url: process.env.NEXT_PUBLIC_SITE_URL ?? "https://example.dev",
};

設定できる場所を減らすと、間違える場所も減ります。

独自ドメインを取ると、この問題は消える

*.vercel.app に依存しなくなるので、推測も混同も起きません。

.dev なら年間十数ドルです。認証を絡めるプロジェクトなら、最初にドメインを取ってしまうほうが安全だと考えるようになりました。

まとめ

  • ***.vercel.app は Vercel 全体で共有される先着順の名前空間。**プロジェクト名から推測できない
  • **本番URLは管理画面からコピーする。**一文字も推測しない
  • **手順書に「記入例」としてURLを書かない。**例は例として読まれない
  • **OAuth の承認済みリダイレクトURIは最後の砦。**ワイルドカードで緩めない
  • 環境変数で設定できる箇所を減らすと、事故の起きる箇所も減る

この記事は、実際に起きたことをもとに書いています。 相手方のサービス名は伏せてあります。

Vercel認証OAuth個人開発ヒヤリハット