PrismaでSupabaseテーブルを作成した後に確認すべきRLS設定
投稿日: 2025年06月08日
皆さん、Prismaを使ってSupabaseに作成したテーブルのRLS(Row Level Security)は有効になっているでしょうか?
RLS(Row Level Security)とは、フロントエンドから「Supabaseクライアント( @supabase/supabase-js)」を使ってSupabaseデータベースにアクセスする際の権限制御機能です。これが有効化されていないと、悪意あるユーザがテーブルレコードを閲覧・変更・削除できてしまう危険な状態🥶となります。
特に、Prismaでスキーマを定義して npx prisma db push
コマンドでテーブルを作成した場合は、デフォルトでRLSは無効(disabled)になっています(ユーザ操作によって、明示的にRLSを有効化する必要があります)。
RLSが無効なままのテーブルは超無防備で、基本的なJavaScriptの知識・スキルがあれば、誰でもレコードの書き換えや削除ができてしまう状態です。攻撃者😈にとって格好の標的になってしまいます。
RLSの有効/無効の確認は「Supabaseの管理画面」から簡単に確認することができます。以下の Category テーブルのように、テーブル一覧で錠が「開🔓」マークになっている、もしくは詳細パネルで「RLS disabled」になっているときは「RLSが無効(=非常に危険)」な状態です。
この場合、「RLS disabled」のボタンを押下し、「Enable RLS for this table」ボタンを押下すれば、RLS が有効化🎉されます。
ShiftBの第10~11章の課題を進めるにあたってRLSを無効化しておく必要性はありません。必ず有効化しましょう。
ちなみにダイアログに表示されているメッセージ…
You can restrict and control who can read, write and update data in this table using Row Level Security. With RLS enabled, anonymous users will not be able to read/write data in the table.
…は以下のような意味です。
このテーブルに対して、「誰がデータを読んだり書き込んだり更新できるか」を細かく制御できる仕組みが「Row Level Security(行レベルセキュリティ)」です。RLSを有効にすると、ログインしていないユーザ(=匿名ユーザ)は、このテーブルのデータを読んだり書き込んだりすることができなくなります。
一方で、下図の Post テーブルのような表示になっていれば、既に「RLSが有効な状態」です。
RLSを有効にした場合、フロントエンドのSupabaseクライアントからの要求は全て拒否する状態になります。この全拒否状態から「この操作だけはOK」といったルール(RLSポリシー)を少しずつ追加していくのが基本的な RLS の使い方になります。
ShiftBの第10〜11章では、すべてのデータベース操作を「バックエンド側のPrismaクライアント経由で行うこと」を前提としています。そのため、ここではRLSを有効にするだけで十分であり、ポリシーを個別に追加する必要はありません。
RLSを無効にしたまま放置しておくと、悪意のあるユーザ😈によってテーブルのレコードが勝手に読み取られたり、書き換えられたり、削除されたりしてしまうリスクがあります。
「いやいや、そんなことできるわけないでしょ?」と思うかもしれませんが……実は、以下のように .env
に記載している Supabase の「APIエンドポイント」と「ANON_KEY」、そして @supabase/supabase-js
を使うことで、誰でも簡単にテーブルレコードを操作できてしまうのです😵💫
NEXT_PUBLIC_SUPABASE_URL=https://lyxdbdadsueizXXXXXXX.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsI....
「APIエンドポイント」と「ANON_KEY」は環境変数としてアプリに設定していますが、NEXT_PUBLIC_
が付いている時点で「フロントエンド(ウェブブラウザ)から見える情報」になります。つまり、ブラウザで、このウェブアプリにアクセスできる人なら、ちょっと調べるだけで、誰でもエンドポイントやキーの内容を見れてしまいます(これは技術的に防げるものではありません)。
具体的な覗き方は、AIに訊いてみてください。
Next.jsでウェブアプリ開発をしています。いま、環境変数として「NEXT_PUBLIC_SUPABASE_URL=…」や「NEXT_PUBLIC_SUPABASE_ANON_KEY=…」を設定しています。これについて「ブラウザから、このウェブアプリにアクセスできる人なら、読み取ることができるよ。」と聞いたのですが本当ですか?具体的に、どのように読み取ることが可能なのですか?(どのような手段や方法で読み取られるリスクがあるのですか?)
…で、「APIエンドポイント」と「ANON_KEY」が入手できれば、フロントエンドからでも Supabaseクライアント(@supabase/supabase-js
)から、次のようなプログラムを使ってテーブルレコードを操作できてしまいます。
"use client";
import { createClient } from "@supabase/supabase-js";
const Page = () => {
const handleButtonClick = async () => {
// Supabaseのクライアントを作成
const apiUrl = "XXX"; // 入手したAPI URLを設定
const anonKey = "XXX"; // 入手したANONキーを設定
const supabase = createClient(apiUrl, anonKey);
// RLS が無効化されているテーブルには、
// フロントエンドからレコードを挿入できてしまう
try {
const categoryName = "ほげほげ";
const { data, error } = await supabase
.from("Category") // テーブル名を指定
.insert([{ name: categoryName, updatedAt: new Date() }])
.select();
if (error) console.error(error);
} catch (e) {
console.error(JSON.stringify(e, null, 2));
}
};
return (
<main className="p-4 max-w-lg mx-auto">
<button
className="px-4 py-2 bg-slate-800 text-white rounded"
onClick={handleButtonClick}
>
テスト
</button>
</main>
);
};
export default Page;
このプログラムを実行すると、フロントエンドからでも、以下のようにテーブルにレコードが追加できてしまいます。その他、読み取りや、書き換え、削除もできてしまいます。
一方で、RLSを有効化していると「new row violates row-level security policy for table "Category"」というエラーメッセージとともに、処理が失敗したこと(リクエストを拒否したこと)を示す応答が返ってきます。
「え、フロントエンドから直接データベース触れるの?」と思った方もいるかもしれませんが、実は、これが Supabase のひとつのウリにもなっています。
Supabaseでは、バックエンドを自分で用意しなくてもアプリを作れるようにするという方針で、フロントエンドから直接データベースを操作できるクライアント(@supabase/supabase-js
)が提供されています。無論、RLSなどのセキュリティ機能をしっかり設定することが前提になりますが、上手に使えばバックエンドを実装せずに非常にシンプルかつスピーディにアプリ開発が進められるようになる・・・・ようです(僕は、実際に試したことはありませんが。