本文へスキップ

Supabase anon keyとservice role keyの違い:何が開くか

Markdownで表示Claudeで開くChatGPTで開くPerplexityで開く

質問もコピーされます。チャットが空で開いた場合は貼り付けてください。

TL;DR

anon keyは、現在publishable keyと呼ばれ、公開される前提のキーです。anonまたはauthenticatedロールに対応し、何が見えるかはRLSポリシーが決めます。service role keyは、現在secret keyと呼ばれ、service_roleに対応し、RLSを完全に迂回します。私のローカルのテストテーブルでは、RLSがオンでポリシーがないとき、公開キーは0行、secret keyは3行すべてを取りました。publishable keyはブラウザに置き、secret keyはサーバーに置き、一度でも公開されたならローテーションしてください。

Denysです。フルスタック・AIエンジニアです。Supabaseのアプリを引き継ぐとき、私が最初に探すのは漏えいしたsecret keyです。それがあれば、ほかの保護はすべて飾りになるからです。この記事では、各キーが何を開くのかを、確認のために実行したリクエストとともに説明します。

Supabaseのanon keyとは?

anon keyが識別するのは、ユーザーではなくあなたのアプリです。ブラウザやモバイルアプリからのリクエストはすべてこれを持つので、公開されている必要があります。ページのソースから誰でも読めます。このキーだけのリクエストは、Postgresのロールanonとして実行されます。ユーザーがSupabase Authでサインインすると、同じキーがユーザーのトークンと一緒に送られ、リクエストはauthenticatedとして実行されます。RLSポリシーは、この2つのロール向けに書きます。

Supabaseはキーの名前を変えています。API keysガイドでは、新しいキーをpublishable(sb_publishable_…)とsecret(sb_secret_…)と呼び、JWTベースの従来のanonとservice_roleは2026年末までに非推奨になります。その裏にあるロールは変わりません。

キー 従来の名前 Postgresのロール RLSは適用される? 置き場所
Publishable sb_publishable_… anon key anon。ユーザートークンがあればauthenticated はい ブラウザ、モバイルアプリ、配布するものすべて
Secret sb_secret_… service_role key service_role いいえ。このロールはBYPASSRLSを持つ サーバー、Edge Function、cronジョブだけ

Supabaseのanon keyを公開しても安全?

はい。ただし、そのキーが届くすべてのテーブル、ビュー、関数が保護されているならです。キー自体は特別なものを何も与えません。すべてはスキーマにあるgrantとポリシーで決まります。ローカルのSupabaseスタック(CLI 2.109.1、Postgres 17.6)に、偽の注文3行のテーブルを1つ置いて確認しました。

各キーがどのPostgresロールになるか。そして、RLSポリシーがそのリクエストを見るかどうか。Publishable key、未サインイン:Publishable key → ロール anon → RLSが適用される、Publishable key、サインイン済み:Publishable key + トークン → ロール authenticated → RLSが適用される、Secret key:Secret key → ロール service_role → RLSは素通り。
図1. SupabaseのAPI keysガイドより、ローカルスタックで確認、2026年10月23日。
テーブルの状態 Publishable key Secret key
RLSオフ 3行すべて。INSERTは201 Createdを返した 3行すべて
RLSオン、ポリシーなし [] 3行すべて
RLSオン、ポリシーusing (true) 3行すべて 3行すべて
anonへのgrantなし 42501 permission denied。足りないGRANTを示すヒント付き 3行すべて

つまり、publishable keyの安全性は、いちばん弱いテーブルと同じです。RLSのないテーブルや、すべての行を許可するポリシーのあるテーブルは、DevToolsを開いた誰にでも読めます。これがCVE-2025-48757の背景にある穴で、Lovableのショーケースアプリ1,645件のうち170件が公開キーにデータを返していました。

service role keyとは何で、なぜ危険?

secret keyはマスターキーです。BYPASSRLS属性を持つservice_roleとして実行されるため、あなたが書いたポリシーは一切適用されません。上の表の最後の列では、どの状態でも3行すべてを読み取りました。Supabaseのガイドは、置いてよい場所を挙げています。自前で認可チェックをするサーバー、Edge Function、バックグラウンドジョブ、管理ツールです。ガイドにある2つの細部は、実務で重要です。

  • 新しいsecret keyは、ブラウザからのリクエストを拒否します。SupabaseはUser-Agentを見て401を返します。従来のservice_role JWTにはこの確認がないので、漏えいした従来のキーはどこからでも使えます。ゲートウェイでのこの確認がない私のローカルスタックは、secret keyを使ったスクリプトに3行すべてを返しました。
  • secret keyがRLSを迂回するのは、リクエストにユーザーのトークンが付いていないときだけです。サインイン中のユーザーのトークンがあれば、リクエストはそのユーザーのポリシーのもとで実行されます。

secret keyを使うEdge Functionは、誰が呼んでいるかの確認と、所有者や会社での絞り込みを自分で行う必要があります。その下には、それをしてくれるものが何もないからです。

Supabaseのservice role keyはどこにある?

Dashboardでは、プロジェクトのConnectダイアログにURLとpublishable keyがあり、従来のキーを含むすべてのキーはSettings → API Keysにあります。ローカルでは、supabase startとsupabase statusがpublishable keyとsecret keyを表示します。キーは環境変数に置いてください。Next.jsでは、NEXT_PUBLIC_プレフィックスを付けてよいのはpublishable keyだけです。バンドラーは、そのプレフィックスが付いたものをすべてブラウザに送るからです。

service role keyが漏えいしたらどうする?

侵害されたものとして扱ってください。見つけた人は、すべてのテーブルのすべての行を読み書きできました。

  1. 新しいsecret keyを作成し、サーバーをそれに移してから、漏えいしたキーを削除します。漏えいしたのが従来のservice_roleキーなら、解決策は新しいキーへの移行です。publishable keyとsecret keyを作り、アプリを切り替えてから、Settings → API Keysで従来のキーを無効にします。そうしない限り、従来のキーは有効なままです。
  2. ビルド済みのJavaScriptとGit履歴からsb_secret_とservice_roleを検索します。Escapeがvibe codingアプリ5,600件をスキャンしたところ、400件超のシークレットの露出が見つかり、その大半はフロントエンドのバンドルにありました。
  3. 漏えいしていた間に何が変わったかを確認します。新しいユーザー、ロールの変更、削除された行です。

無料のSupabase セキュリティチェックはフロントエンドは読みませんが、同じ問題のデータベース側を読みます。RLSを迂回するロール、RLSがオフのテーブル、すべての行を許可するポリシー、機密に見えて匿名の訪問者が読める列です。公開キーが実際に何に届くかを確認する手順はvibe codingのセキュリティリスクにあり、アプリに対して私が実行する全リストはLovableアプリのセキュリティチェックリストにあります。

自分のアプリがどのキーを配っているか分かりませんか?

見てみて、情報交換できれば嬉しいです。売り込みはありません。

お問い合わせ

© 2026 Denys Zaichenko. 元の記事: https://madsalt.tech/ja/blog/supabase-anon-key-vs-service-role-key/