RLSが効いている証明に、でたらめなIDは使えなかった

転職用のポートフォリオとして、個人でWebアプリ「Hubpin」を作っています。
制作の経緯は「Hubpin 開発記録」に時系列でまとめています。
設計と判断は自分で行い、実装も原則自分で書いています。AIには手順書・レビュー・調査を任せています。

Supabase の RLS(行単位のアクセス制御)についてのシリーズ4本目です。
これまでの3本は RLS の挙動そのものの話でしたが、今回は検証する側の話です。

他人のデータが見えないことを確認しようとして、404 を3回出しました。
証明になったのは3回目だけでした。

目次

確認したかったこと

作っていたのは、自分のカードを編集するページです。URL にカードの ID が入ります。
確認したかったのは「他人のカードの ID を URL に入れても、中身が見えないこと」でした。

RLS が効いていれば、他人の行はデータベースから 0 行で返ってきます。
アプリ側はデータが無いので、404 を出します。
なので、他人の ID を入れて 404 になれば OK。そう考えていました。

404 を3回出したが、意味が3回とも違った

開いた ID 何が起きたか 何を証明したか
ユーザー名の文字列 UUID に変換できずデータベース側でエラー(22P02 何も。エラーの確認になっただけ
他人のユーザー ID カードの表にその ID の行が無い 何も。ただ存在しないだけ
他人のカードの ID 行は実在するのに 0 行で返る RLS が隠したと確かめられる

1回目は、そもそも ID の形式になっていませんでした。
2回目は、ID の形式としては正しいけれど、カードの表には存在しない値でした。
どちらも「無いから404」であって、RLS は何もしていません。

3回目でようやく、行が実在していて、しかも 0 行で返ってくる状態になりました。
実在するのに返ってこない。
ここで初めて、RLS が隠した結果だと確かめられます。

3回目の ID は、Supabase の管理画面で実在する行を探して特定しました。
手で探しに行かないと作れない条件でした。

3つとも、画面はまったく同じ404だった

怖かったのはここです。3回とも、ブラウザに出る画面は同じ404でした。

自分のアプリは、「存在しない」と「他人のもの」を区別しない設計にしています。
区別して「権限がありません」と出すと、そのIDが存在することを教えてしまうからです。
これは意図してそうしました。

ただ、その設計は検証する側にも同じ壁を立てます。
画面だけ見ていたら、3回とも「他人のカードは見えない、成功」と読めてしまう。
実際、2回外していました。

経路が1本しかないかを見る

ここから持ち帰ったのは、検証の見方です。

「期待どおりの結果が出たか」だけでは足りなくて、「その結果に至る経路が1本しかないか」を見る。

今回、404 が出たこと自体は3回とも同じでした。
違ったのはなぜ404になったかのほうで、それは ID の選び方でしか作り分けられません。
画面には出ないので、選び方を間違えると、確かめたつもりのまま通ってしまいます。

設計上そうしたことで、自分の検証も難しくなる。
その分だけ、確認の手順を丁寧に作る必要がありました。

目次