DBの権限を見直したら、RLSが効かない権限が全テーブルに付いていた

自分の発信を1か所に集めるハブサイト「Hubpin」を、個人で作りました。
制作の経緯は「Hubpin 開発記録」に時系列でまとめています。
Claude Code を取り入れながら、設計から実装まで一人で進めています。

データベースには行単位のアクセス制御を入れてあります。
自分の行だけが見える、自分の行だけが書き換えられる、という設定です。

入れてあるので、そこは大丈夫なつもりでいました。

工程の区切りで権限の一覧を見に行ったら、全部のテーブルに余計な権限が付いていました。

目次

テーブルごと空にする権限が残っていました

付いていたのは、テーブルの中身をまとめて消す権限でした。
3つのロールと5つのテーブル、全部の組み合わせに付いています。

作り始めたころに、まとめて全権限を渡す書き方をしていた名残でした。

そのあと必要なぶんだけに絞っています。
ただ、絞った対象が読み取りと追加と更新と削除の4つだけで、それ以外の権限は触っていませんでした。

ここだけ、行単位の制御が効きません

問題は、この権限が行単位の制御の外にあることでした。

行ごとのルールが適用されるのは、読み取り、追加、更新、削除の4つです。
テーブルごと空にする操作は、テーブル単位の権限として動くので、行のルールを一切見ません。

行単位の制御を入れてあるから大丈夫、というのが、ここだけ通じませんでした。

今は届かないと分かったうえで、剥がしました

念のため、その権限に届く経路があるかを調べました。

アプリが使っているAPIの層は、そもそもその操作を発行しません。
データベース側に置いた関数からも呼べないことを、1つずつ確認しました。

つまり、いまこの瞬間は誰も届きません。

それでも剥がすことにしました。

今は届かない、というのは、いま手元にある部品がその経路を使っていないというだけです。
経路そのものが閉じたわけではありません。
関数を1つ足した日に、行の制御が効かない場所として残ります。

1行のマイグレーションで剥がして、権限の一覧と、公開ページと、ログイン後の画面を見て、動くことを確かめました。

翌日、すぐ隣に同じ形が残っていました

これで終わりだと思っていたら、翌日の全体レビューで続きが出ました。

画面をひとつも作っていないテーブルに、書き込みの権限が開いていました。

行を守るルールも入ってはいたのですが、持ち主だけを見ていて、どのカードに紐づいているかを見ていません。
表示する側も、そのテーブルの持ち主を確かめていませんでした。

この組み合わせだと、他人のページに自分のデータを並べられる形になります。

こちらも1行で塞ぎました。

2ヶ月前にも、同じ形を1件直していました

ここが引っかかったところです。

2ヶ月前にも、画面が無いのに書き込み権限が開いている、という状態を1件直しています。

同じ形が、別のテーブルで、2ヶ月後に出ました。

1度直したときに直っていたのは、そのとき見た1枚だけでした。

画面から辿ると、画面の無いところが残ります

2件とも、画面を作っていない場所で起きています。

画面が無いから書けない、とどこかで思っていました。
画面を作っていないことは、権限を閉じた理由にはなりません。

絞ったときも同じです。
使う操作を4つ挙げて、それだけ許可したつもりでした。
実際には、4つについては考えて、残りについては考えていませんでした。

権限は画面から辿るのではなく、権限の一覧のほうから見るしかなさそうです。

目次