フロントエンドにデータベースの鍵を渡す時
従来のソフトウェアアーキテクチャでは、データベースは地下室にある金庫のようなものでした。フロントエンド(ブラウザ)が直接この金庫に触れることは絶対にありません。ウェブページは「バックエンドサーバー(Node.jsやPythonなど)」を警備員として経由し、警備員がユーザーの身分証を確認した後、自ら地下室へ行って金庫からデータを取り出します。
しかしクラウド技術とSupabaseの台頭により、「サーバーレス(Backend-as-a-Service)」という開発アーキテクチャが流行しています。
第2章では、Supabaseのanon_keyを直接.env.localに配置し、Next.js/Reactフロントエンドが直接接続してデータを取得する方法を教えました。
これは前例のない開発速度をもたらしますが、同時に巨大なセキュリティホールも生み出します:もし悪意のある人物がウェブページでF12開発者ツールを開き、あなたのanon_keyを盗んだらどうなるでしょうか?
この鍵を使ってDELETE FROM users(全ユーザー削除)のようなスクリプトを実行された場合、あなたの努力は一瞬で無に帰します。
この致命的な問題を解決するため、PostgreSQLはその最強の防御兵器を繰り出します:RLS(Row-Level Security、行レベルセキュリティ)。
RLSとは?各行データに専属ボディーガードを配備
従来のデータベース権限は「玄関のセキュリティ」のようなものです。ハッカーがorders(注文)テーブルに侵入すると、全員の注文を見ることができてしまいます。
RLS(Row-Level Security)の概念は全く異なります。これはテーブル内の「各行(Row)」に武装したボディーガードを配置するようなものです。
ハッカーがanon_keyを使って王大明の注文を取得しようとすると、ボディーガードが即座に阻止します:
「JWT通行証を提示してください!あなたが『王大明本人』であることを証明しない限り、このデータを取得することは許可できません。さもなければ、このテーブルでは何も見えません!」
RLSの保護があれば、たとえanon_keyが漏洩してもハッカーは無力です。anon_keyは単なる「ノック」の手段であり、RLSが「ドアの向こうに何を表示するか」を決定するからです。
RLSの核心:Policy(ポリシー)
Supabaseでこれらのボディーガードを訓練するにはどうすればよいでしょうか?各テーブルに対して**Policy(ポリシー)**という法律条文を作成する必要があります。
ポリシーは通常2つの要素で構成されます:
- 許可する操作(Action):例)
SELECT(読み取り)、INSERT(追加)、UPDATE(更新)、DELETE(削除) - 許可条件(USING/WITH CHECK):例)「現在ログインしているユーザーのIDがこの行のuser_idと等しい場合」
一般的なRLSビジネスシナリオ設定
シナリオ1:公開商品カタログ(全員閲覧可能)
products(商品テーブル)では、ログインしている会員でも通行人でも商品情報を閲覧できるようにします。ただし、誰も商品を変更また���削除することは許可しません。
- 操作:
SELECTを許可 - 条件:
true(無条件で全員許可) - (注:
INSERTやUPDATEのポリシーを書いていないため、商品を変更しようとする試みは全てボディーガードにブロックされます!)
シナリオ2:個人のショッピングカートと注文(自分だけが見られる)
orders(注文テーブル)は極めてプライベートなデータです。王大明は王大明の注文しか見えず、陳小美が何を購入したかは絶対に見えてはいけません。
- 操作:
ALLを許可(クエリ、追加、更新、削除を含む) - 条件:この行の
user_idが**現在ログインしているユーザーのUID(auth.uid())**と等しくなければならない
実戦:Vibe PromptでRLS設定問題を瞬時に解決
RLSは強力ですが、そのSQL構文は非常に冗長で間違いやすいものです。Vibe Codingでは、RLSポリシーを手書きするべきではありません。
Supabase開発中に「データは確かに保存されているのに、フロントエンドで取得しようとすると空っぽ」という状況に遭遇したら、100%RLSファイアウォールに衝突しています。この時はCursorのSQL Editorを開き、AIにこの究極の解除呪文を入力してください:
【Supabase RLS解除Prompt】 Supabaseを使用しています。
user_profilesというテーブルがあり、フィールドはid(auth.usersに関連)、nickname、avatar_urlです。 RLSのため、フロントエンドでデータを読み取ったり更新したりできません。 以下のRLSポリシー設定を行う完全なSQLスクリプトを作成してください:
user_profilesのRLS機能を有効化(ENABLE ROW LEVEL SECURITY)- 最初のポリシー:「誰でも(匿名訪問者を含む)」が全員のデータを読み取る(
SELECT)ことを許可- 2番目のポリシー:「ユーザー本人」のみが自分のデータを更新(
UPDATE)または追加(INSERT)できるようにする(条件はauth.uid()がこの行のidと等しいこと) SupabaseのPostgreSQL環境に完全に互換性のある構文でお願いします。
AIが生成する神レベルのボディーガード訓練スクリプト:
-- 1. テーブルのボディーガードシステムを起動(RLS有効化)
ALTER TABLE user_profiles ENABLE ROW LEVEL SECURITY;
-- 2. ポリシー1:全員が閲覧可能(SELECT)
CREATE POLICY "Public profiles are viewable by everyone"
ON user_profiles
FOR SELECT
USING (true);
-- 3. ポリシー2:本人のみ追加可能(INSERT)
CREATE POLICY "Users can insert their own profile"
ON user_profiles
FOR INSERT
WITH CHECK (auth.uid() = id);
-- 4. ポリシー3:本人のみ更新可能(UPDATE)
CREATE POLICY "Users can update own profile"
ON user_profiles
FOR UPDATE
USING (auth.uid() = id);
このスクリプトをコピーしてSupabaseのSQLコンソールに貼り付け、実行するだけです。 瞬く間に、あなたのデータベースは軍事レベルのセキュリティ保護を獲得します。完成したウェブページをクライアントに安心して引き渡せ、ハッカーによるデータベース破壊を心配する必要はもうありません!
おめでとうございます!この章を完了したあなたは、現代のデータベースにおける「構築、リレーショナル演算、暗号化、最高レベルのRLSセキュリティ保護」までの完全なエコシステムをマスターしました。強力なVibe Coderとして、世界中のあらゆるデータがあなたの意のままになります!
更多 RLS 應用場景
多租戶應用
-- 每個使用者只能看到自己的資料
CREATE POLICY tenant_isolation ON orders
USING (tenant_id = current_setting('app.tenant_id')::INT);
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
唯讀管理員
-- 管理員可以讀取所有資料,但只能寫入日誌表
CREATE POLICY admin_read_all ON products FOR SELECT
USING (true);
CREATE POLICY admin_write_logs ON audit_logs FOR INSERT
WITH CHECK (true);
效能注意事項
- RLS 會增加每次查詢的開銷,特別是在複雜的政策中
- 對於頻繁存取的表格,建議使用索引來加速政策評估
- 在高吞吐量的系統中,考慮使用應用層授權代替 RLS