付録C 普通のDB(PostgreSQL / MySQL)入門 — RLSがない世界での守り方

📖 このページのゴール:Supabase(RLS)の外=一般的なデータベースでは、「自分のデータだけ」をどうやって守るのかを知る。 ← 目次・はじめにへもどる


本編の第4章では、Supabaseの RLS という機能で「自分の行だけ」を守りました。でも、世の中のアプリが全部RLSを使っているわけではありません。RLSがない場所では、別のやり方で守ります。 その「別のやり方」を、ここで見ておきます。


🤔 RLSは特別な機能(🟢 基礎)

まず大事な前提から。RLS(行レベルセキュリティ)は、もともと PostgreSQL(ポストグレス)というデータベースの機能です。すべてのデータベースに付いているわけではありません。

  • MySQL(マイエスキューエル)には、RLSがありません。
  • 素の PostgreSQL でも、第4章でやったように 自分で明示的にONにしないと働きません。

🏤 たとえ話:建物によって設備が違う RLSは「各部屋に最初から付いている自動ロック」のようなもの。でも、そういう設備がない建物(MySQL)もあるし、付いていてもスイッチを入れ忘れている建物(素のPostgreSQL)もあります。

だから、世の中の多くの現場では RLS に頼らず、「アプリ側のコードで、取り出すたびに自分でしぼる」 という方式をとっています。次はその方式です。


🛠 RLSがない世界の守り方(🟢 → 🔧 実装)

やることは1つだけ。データを取り出す命令に、毎回かならず「ログイン中の人のものだけ」という条件を付けることです。

サーバー側のコードは、こんなSQLをデータベースに送ります。

-- ログイン中ユーザーのIDを $1 に渡す(プレースホルダ)
select * from tweets where user_id = $1 order by created_at desc;

1行ずつ読むと、こうです。

  • select * from tweets … 「tweets(ツイート)表から、全部の列をちょうだい」(* は「全部の列」)。
  • where user_id = $1 … ★ここが守りの本体。「user_id(持ち主)が $1 と一致する行だけ」にしぼる、という条件。
  • $1プレースホルダ(差し込み口)。値を直接SQLの文字列に埋め込まず、あとから安全に渡す仕組み。これは後述のSQLインジェクション対策にもなります。
  • order by created_at desc … 「created_at(投稿時刻)で 新しい順に並べて」(desc = 降順)。

ここで一番大事なのは、$1(ログイン中の人のID)を誰が決めるかです。答えは サーバー。サーバーはログイン状態(セッション)から「いまアクセスしているのは誰か」を知っているので、その人のIDを $1 に入れます。

⚠️ クライアント(ブラウザ)の言い分は信用しない。 「自分は3番さんです」とブラウザが送ってきても鵜呑みにしません。なりすませてしまうからです。持ち主の判定は、必ずサーバーが握る——これは第4章の auth.uid() と同じ考え方です。

🔌 接続(コネクション)の一言:アプリはまずデータベースに「接続(コネクション)」をつないでから、こうした命令を送ります。Supabaseを使っていたときは、この配管(接続)も全部Supabaseが裏で用意してくれていました。


🔁 SupabaseのRLS ↔ 普通のDB 対応表

同じ「自分のだけ見せる」を、2つの世界はこう実現します。

  Supabase の RLS 普通のDB(素のPostgreSQL / MySQL)
誰がしぼる? データベースが自動で アプリが毎回 手でwhere を書く)
付け忘れたら? それでも守られる(DBが最後の砦) そこから全部 漏れる 😱
向いている人 初心者・少人数(仕組みに任せたい) 仕組みを自分で握りたい上級者

ひとことで言うと、RLSは「DBが守ってくれる」/普通のDBは「自分で守る」 です。便利さと引きかえに、普通のDBでは1か所の書き忘れが命取りになります。


🐘 PostgreSQL と 🐬 MySQL のざっくり違い

どちらも、世界中で使われている定番の リレーショナルDB(表=テーブルでデータを管理するデータベース)です。初心者のうちは「どっちも表でデータを保存する仲間」という理解で十分です。

  • 🐘 PostgreSQL … RLSのような高機能な仕組みも持つ、多機能寄りのDB。Supabaseの中身はこのPostgreSQLです。
  • 🐬 MySQL … とても広く普及していて、シンプル寄り。Webサービスの定番として長く使われてきました。

どちらが正解ということはなく、現場の事情で選ばれます。この教材でRLSが使えたのは、たまたま土台がPostgreSQLだったから、と覚えておくと混乱しません。


⚠️ ハマりどころ

  • where の付け忘れ = 穴。 普通のDB方式では、where user_id = $1書き忘れた瞬間、その命令は全員ぶんを返します。RLSと違い、DBは助けてくれません
  • SQLを文字列でつなげない(インジェクション)。 "... where user_id = " + 入力値 のように値を文字列連結すると、悪意ある入力で命令を乗っ取られます(SQLインジェクション)。必ずプレースホルダ($1 など)を使うこと。
  • 1か所の漏れが全体に波及する。 しぼる責任がアプリ側に散らばるので、どこか1本のSQLがミスっていると、そこだけ筒抜けになります。この「事故りやすさ」は第10章でも扱います。

📝 ことばメモ

  • RLS(行レベルセキュリティ):DBが「行ごとに、触っていい人か」を自動でチェックする仕組み。PostgreSQL専用で、MySQLには無い
  • プレースホルダ:SQLに値を直接埋め込まず、$1 のような差し込み口であとから安全に渡す仕組み。インジェクション対策になる。
  • SQLインジェクション:入力値を文字列連結でSQLに混ぜたとき、命令を乗っ取られる攻撃。プレースホルダで防ぐ。
  • コネクション(接続):アプリがDBに命令を送るためにつなぐ通信路。Supabaseでは隠れていた配管。
  • リレーショナルDB:表(テーブル)でデータを管理するタイプのデータベース。PostgreSQLもMySQLも仲間。

🔧 ちなみに、SQLを自分で書かずにデータベースを扱う「ORM」という道具もあります。これは付録Dで扱います。


← 目次・はじめにへもどる