なぜ危ないのか
Supabaseのanon keyはクライアントサイドに公開することを前提に設計されているが、それはRow Level Security(RLS)が適切に設定されていることが大前提だ。AIが生成したHTMLにはRLSの設定情報が含まれないため、RLSが無効なテーブルへのanon keyを埋め込んだ場合、全行を読み取られるだけでなくINSERTやDELETEまで実行されうる。
さらに問題なのは、AIがanon keyをJavaScriptの変数として直接書き込む点だ。`const SUPABASE_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'`のような形式で埋め込まれると、ファイルをそのままメールで送信した場合やブラウザの「ソースを表示」で丸見えになる。特にJWTはBase64デコードするとプロジェクトURLやロールなど付加情報が含まれており、攻撃の手がかりになりやすい。
- 相手がログインなしで開ける状態か確認する
- PCとスマホで最低1回ずつ表示を確認する
- 内部情報・個人情報・不要な外部送信が残っていないか見る
- レビュー期限と修正時の差し替え方を決めておく
ソースで見る場所
HTMLファイルで `eyJ` という文字列を検索するのが最速だ。JWTはBase64エンコードされたヘッダーが `eyJhbGciOi` で始まるため、このプレフィックスを検索するだけでanon keyや他のJWTトークンを網羅できる。VS Codeなら Ctrl+F で `eyJ` を入力、ファイル内に一致があればその行を確認する。
`supabase.createClient` や `createClient(` の呼び出し箇所もチェックポイントだ。第2引数にキーが直接書かれていることが多い。また、`SUPABASE_ANON_KEY`・`anonKey`・`anon_key` のような変数名で定義されているケースもあるため、これらのキーワードでもファイル内を検索しておくと見落としを防げる。
- HTML内の外部script・form action・iframeを確認する
- APIキーやトークンらしき文字列がないか検索する
- 画像・CSS・JSのパスが公開後も解決できるか見る
- noindexと認証を混同せず、必要なら両方設定する
安全に共有する設定
anon keyが見つかった場合は、まずSupabase管理画面でそのプロジェクトのRLS設定を確認し、全テーブルでRLSが有効になっているかチェックする。有効でない場合はHTMLを共有する前にRLSを有効化するか、keyをプレースホルダに置き換えた状態でファイルを渡す。プレースホルダに置き換えたファイルであれば、Supabaseへの接続そのものができないため情報漏えいのリスクはない。
ギガサイト便などのプレビュー共有サービスを使う場合も同様で、アップロード前にkey置換を行い、認証付きのURLで共有する。レビュー完了後はプレビューリンクを失効させることを忘れずに。もし動作確認が必要なデモ環境を共有したい場合は、Supabase上にテスト用プロジェクトを別途作成し、本番データを含まない状態でデモ用anon keyだけを使うよう切り替えるのがベストプラクティスだ。
- HTML内の外部script・form action・iframeを確認する
- APIキーやトークンらしき文字列がないか検索する
- 画像・CSS・JSのパスが公開後も解決できるか見る
- noindexと認証を混同せず、必要なら両方設定する
再発防止ルール
AIへのHTMLプロンプトに「Supabase接続情報(URL・anon key)は変数宣言にせず、`SUPABASE_URL`・`SUPABASE_ANON_KEY`というプレースホルダテキストを使うこと」と明示する。この制約を最初の行に入れるだけで、AIは実際のキー値を出力しなくなる。生成後の確認工数が大幅に下がる。
チームでのレビューフローにも組み込む。コードレビューのチェックリストに「`eyJ`でHTMLを全文検索してJWTがないことを確認」という項目を追加し、Merge/公開前に必須確認とする。CIがある場合は`grep -r 'eyJ' ./public/`をチェックジョブとして追加すると自動化できる。
- HTML内の外部script・form action・iframeを確認する
- APIキーやトークンらしき文字列がないか検索する
- 画像・CSS・JSのパスが公開後も解決できるか見る
- noindexと認証を混同せず、必要なら両方設定する
よくある質問
anon keyはservice_role keyとどう違い、どちらがより危険ですか?
service_role keyはRLSを完全に無視してすべてのデータを読み書きできるため、anon keyより格段に危険だ。HTMLに含まれてはならないのはservice_role keyで、anon keyはRLS設定が正しければ比較的安全だが、それでも本番データへの不用意なアクセスを防ぐため公開HTMLには含めないのが原則だ。
誤ってanon keyをメールで送ってしまいました。どう対処すればよいですか?
Supabase管理画面の「API」セクションからanon keyを再生成(ローテーション)する。再生成後は旧キーが無効になるため、正規のクライアントアプリに新キーを反映させる必要がある。同時に、RLSが全テーブルで有効になっているか確認しておく。
デモ用途でanon keyをHTMLに含めることは絶対に避けるべきですか?
Supabase側でRLSを有効にし、デモ用の読み取り専用データのみ閲覧を許可するポリシーを設定しているなら、限定的には許容できる。ただし本番データが含まれるプロジェクトのキーをデモに流用するのは避け、必ずサンドボックス用の別プロジェクトを使うこと。