転職用のポートフォリオとして、個人で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 の選び方でしか作り分けられません。
画面には出ないので、選び方を間違えると、確かめたつもりのまま通ってしまいます。
設計上そうしたことで、自分の検証も難しくなる。
その分だけ、確認の手順を丁寧に作る必要がありました。
