---
title: "Supabase anon keyとservice role keyの違い：何が開くか"
description: "anon key（publishable）がブラウザで安全なのはRLSがあるときだけで、service role key（secret）はRLSを迂回します。それぞれの置き場所を、ローカルで検証しました。"
url: "https://madsalt.tech/ja/blog/supabase-anon-key-vs-service-role-key/"
author: "Denys Zaichenko"
language: "ja"
published: 2026-10-25
---

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

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ガイド](https://supabase.com/docs/guides/api/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は素通り。](https://madsalt.tech/charts/ja/supabase-anon-key-vs-service-role-key.svg)

*図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](https://mattpalmer.io/posts/2025/05/statement-on-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件超のシークレットの露出](https://escape.tech/blog/methodology-how-we-discovered-vulnerabilities-apps-built-with-vibe-coding/)が見つかり、その大半はフロントエンドのバンドルにありました。
3. 漏えいしていた間に何が変わったかを確認します。新しいユーザー、ロールの変更、削除された行です。

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

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

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

[お問い合わせ](https://madsalt.tech/ja/#contact)
