RLSを設定したから安全、とは言えないSupabaseの5ケース

RLSを設定したから安全、とは言えないSupabaseの5ケース

記事
IT・テクノロジー
Supabase を使っていると、「RLS(行単位のアクセス制御)を設定したので、他の人のデータは見えないはず」と考えがちです。実際、RLS は強力な仕組みです。

ただ、RLS を書いたこと自体は、安全であることの証明にはなりません。私は自社の SaaS を一人で開発・運用していて、自分のコードを点検したときにも「効いていると思っていたが、確認できていなかった」箇所が出てきました。

ここでは、RLS を設定していても穴が残る典型的なケースを5つ挙げます。ご自身のプロジェクトで確認する手がかりになれば幸いです。

──────────

■ ケース1:そもそも RLS が有効化されていない表がある

Supabase は、明示的に有効化しない限り RLS がかかりません。

ALTER TABLE テーブル名 ENABLE ROW LEVEL SECURITY;

この一行を書き忘れた表は、公開用の anon キーだけで全件読み出せる状態になります。ポリシーをいくら丁寧に書いても、有効化していなければ意味がありません。

確認方法は、SQL Editor で次を実行するだけです。

SELECT tablename FROM pg_tables
WHERE schemaname = 'public' AND rowsecurity = false;

ここに何も出なければ、この点は問題ありません。

──────────

■ ケース2:マイグレーションに定義がない表がある

管理画面から直接テーブルを作ると、リポジトリに定義が残りません。

私が自分のコードを数えたときは、コードが読み書きしている29の表のうち、マイグレーションに定義があるのは14でした。残る15は、リポジトリのどこを見ても定義が見つからない状態でした。

このとき問題なのは「危険である」ことではなく、「危険かどうかを確認できない」ことです。RLS が有効なのかもしれませんが、コードからは判断できません。検証用の環境を作り直すこともできません。

この2つは対応の優先度が変わるので、区別して考えることをおすすめします。

──────────

■ ケース3:会社IDを user_metadata から取っている

マルチテナントのアプリで、ログイン中の利用者がどの会社に属するかをどこから取っているかは、決定的に重要です。

・DBのメンバー表を引く → 問題ありません
・JWT の app_metadata → 問題ありません
・JWT の user_metadata → 危険です
・リクエストのパラメータをそのまま使う → 危険です

user_metadata は、利用者自身が更新できる領域です。ここに会社IDやロールを置くと、利用者が自分で書き換えられます。

リクエストの値をそのまま使っている場合も同様で、他社のIDを送れば他社のデータが返ります。

──────────

■ ケース4:INSERT のポリシーに WITH CHECK がない

ここは誤解されやすいところです。

・UPDATE のポリシーで WITH CHECK を省略した場合
 → PostgreSQL は USING の条件を更新後の検査にも流用します。したがって問題ありません。

・INSERT のポリシーで WITH CHECK がない場合
 → 検査が一切かかりません。他社のIDを指定した行を作れてしまいます。

同じ「WITH CHECK がない」でも、操作によって意味がまったく違います。UPDATE の方を指摘してしまうと、かえって精度を疑われます。

──────────

■ ケース5:service_role キーを使う経路

service_role キーは RLS を丸ごと迂回します。管理系の処理や Webhook の受信で使うことが多いと思います。

問題は、その経路では認可を自分で書かなければならない点です。RLS が守ってくれないので、書き忘れるとそこだけ全件見える状態になります。

私のコードでは14箇所で使っていました。1つずつ確認したところ、いずれも意図した通りに保護されていましたが、共通の目印がなく一覧もない状態でした。15箇所目を足したときに認可を書き忘れても、テストも型検査も通ってしまいます。

grep で洗い出して、1箇所ずつ「実行前に誰であるかを確認しているか」を見ていくのが確実です。

──────────

■ 最後に:テストで固定されているか

RLS もサーバー側の判定も、壊れたときに気づける仕組みがなければ、いずれ壊れます。

ポリシーの条件を1文字消しても、ロジック層のテストは全部通ります。「動いている」ことは確認できても、「破れない」ことは確認できていない、という状態です。

利用者2名分のアカウントを用意して、次の3本だけでも書いておくと、改修時の事故を止められます。

1. 利用者Aの権限で、利用者Bのデータを取得しようとして失敗すること
2. URLのIDを他人のものに書き換えたとき、403か404が返ること
3. 公開用のキーで直接DBに接続したとき、何も取れないこと

──────────

ここに書いた5点は、一般論ではなく、自分のコードを実際に点検して出てきたものです。

「動いてはいるが、このまま公開していいのか分からない」という状態は、AIツールで開発している方には珍しくないと思います。ご自身で確認される際の手がかりになれば幸いです。

出品サービスでは、この観点でコードを読んで、重要度つきのレポートにしてお渡ししています。ご相談だけでも構いませんので、お気軽にどうぞ。
サービス数40万件のスキルマーケット、あなたにぴったりのサービスを探す