本文へスキップ

PRODUCT

Supabaseとは?個人開発で使える機能と権限設計の注意点

石井和秀 · ClearDropSHARE

Supabaseでできることと、個人開発でつまずく行単位の権限を3本のアプリで使う立場から整理。権限を締めて本番を止めた失敗と、触る順番も書きます。

積み重なった層の一つだけに鍵の印が付いている図
この記事の目次

Supabaseは、データベース・認証・ファイル保存・サーバー処理をまとめて用意してくれるサービスです。私は3本のアプリで使っています。便利な反面、権限の設定を触って本番を止めたこともあるので、できることと、詰まりやすいところを並べて書きます。つまずくのはほぼ一箇所で、アプリから直接データベースを触れる代わりに、誰が何を読めるかを自分で設計するところでした。開けすぎと閉めすぎの両方をやった記録です。

Supabaseで何ができるのか。三本で使っている範囲

中身はPostgreSQLというデータベースで、その周りに個人開発で必要になるものが揃っています。自分でサーバーを立てずに、アプリのデータを置けるのが一番の利点です。

私が実際に使っているのは、データの保存、ログイン、画像などのファイル保存、そして軽いサーバー処理です。たとえばコースを作る処理や、課金の状態を受け取る処理をここに置いています。

ブラウザの管理画面からテーブルを作れて、そのまま使えます。設計を変えたくなったときも、画面から直せる手軽さがありました。ただし、画面で直した変更は手元に残りません。変更をファイルとして残す仕組みを早めに用意しておくほうが、あとで困りません。私は途中からそうしました。

個人開発で効いた点を並べると、下のようになります。最後の一つが一番効きますが、次の節の注意と表裏です。

  • ログインの仕組みを自分で作らなくてよい。匿名のままの利用も選べる。
  • データの構造を、普通のデータベースとして設計できる。
  • 画像や添付をそのまま置ける。
  • サーバー処理を短い関数として置ける。常時動くサーバーを持たずに済む。
  • アプリから直接読み書きできるので、間にAPIを自作しなくてよい。
間に自作のサーバーを挟まないので、書く量が減ります。ただし、自作のサーバーが担っていた「誰に何を返すか」の判断は消えません。こちらで別の形で持つことになります。

一番のつまずきどころは、行単位の権限(RLS)

アプリから直接データベースを触れるということは、誰が何を読めるかをデータベース側で決めなければいけないということです。ここを担うのがRLS(行レベルセキュリティ)と呼ばれる仕組みです。

「このテーブルは、自分のデータだけ読める」「ログインしていない人は書けない」といった条件を、テーブルごとに書きます。書き忘れると、誰でも全部読める状態になります。逆に厳しく書きすぎると、正規の利用者まで弾かれます。

私はこれで一度、本番を止めました。監査で見つかった緩い権限をまとめて締めたところ、アプリの主要なデータが読めなくなったのです。締めた対象の中に、権限の判定そのものが使っていた補助の関数が混じっていました。

守るための仕組みを、守ろうとして壊した形です。このときの経緯はセキュリティを強くしようとして、本番を止めた。RLSの見落としに書きました。

教訓は、権限は「厳しくすれば安全」ではないということでした。必要な経路まで閉じれば、ただ壊れます。攻撃する人を締め出したつもりで、正規の利用者も締め出していました。

もう一つ分かったのは、一括で変えたことが原因を見えなくしたという点です。まとめて締めたので、どの変更が効いたのか切り分けられませんでした。一度に変えるのは一つ、という当たり前のところで転んでいます。

権限を触るときの順番。五つに分けて進める

事故のあと、権限を触るときの順番を決めました。急いでいるときでも、この順番だけは崩さないようにしています。

  1. 01 外から呼ぶものと、内部で使うものを分ける

    名前や置き場所が似ていても、呼ばれる相手が違えば必要な権限が違います。同じ一覧として扱うと、内部で使うものまで閉じてしまいます。私が止めたのはここでした。

  2. 02 本番ではなく、狭い環境で先に試す

    本番でいきなり変えません。影響を限定できる場所で、期待する拒否と許可の両方を確かめます。

  3. 03 利用者が通る経路を全部試す

    これが抜けやすい。同じデータでも、アプリからの直接読み取りと、関数経由では通る境界が違います。片方だけ確認して終わらせないことです。

  4. 04 拒否されるべき側も動かして試す

    ログインしていない要求、他人のデータへの要求。許可の確認だけだと、開けすぎていても気づきません。

  5. 05 戻し方を書いてから適用する

    本番で問題が出たときに、慌てて広く開け直すと監査で見つかった穴まで戻ります。戻す手順を先に書いてから適用します。

クライアントを信用しない。判定はサーバー側に置く

もう一つ、設計で気をつけていることがあります。判定はサーバー側で行うことです。

距離の条件、年齢の条件、定員、課金しているかどうか。こうした判定をアプリ側だけで行うと、アプリを書き換えられた場合に通ってしまいます。データベースの条件か、サーバーに置いた関数で判定します。

回数の制限も同じです。1日に何回使えるかをアプリ側で数えると、入れ直せば戻ります。サーバー側に記録して、そこで数えます。課金の状態も同様で、アプリが持っている情報だけを信用しないようにしています。

判断の目安は単純で、そこを突破されて困るなら、サーバー側で判定する。困らないもの、たとえば表示の並び順や見た目の切り替えは、アプリ側で構いません。

ここで一度つまずいたのは、確認するコードそのものが間違っていたときです。利用者が自分で決めたかどうかを調べるつもりの判定が、部品側が登録した既定値まで拾う書き方になっていて、切るべき場面で切らない結果を返していました。⚠️ 判定を書いたら、判定が正しいかも確かめます。

この考え方は、外部の部品を入れるときにも効きます。自分が書いた行の外側で何が起きているかまで見る話は生成AIの回答は正しい?そのまま採用する前に通す確認5つにも書きました。

向いている場合と、向かない場合を先に見る

向いているのは、普通のデータベース設計で表現できるアプリです。一覧があって、詳細があって、利用者ごとにデータが分かれる。私が作っているものは全部これに当てはまります。

向かないのは、データの形が固まっていない段階で作り始めるときでした。テーブルを設計してから動かすので、形が毎日変わるうちは手間が勝ちます。そのときは、まず手元で動くものを作って、形が決まってから移すほうが早いことがあります。

あとは、すでに別の仕組みで動いているものを途中で移すのは重い作業です。認証まわりは特に、利用者のアカウントをどう引き継ぐかの問題が残ります。始める前に、あとで別の場所へ持っていけるかを一度考えておくと安心です。データそのものは普通のデータベースなので、持ち出し自体は難しくありません。

最初に作るときの順番も決めてあります。次の五つのうち、2番目と3番目を飛ばしがちです。自分のアカウントでは正しく見えるので、そこで満足してしまう。別のアカウントと、ログインしていない状態の2つを試すだけで、開けすぎている状態はほぼ見つかります。

使う前に把握しておきたい点は下の表にまとめました。最後の行の「データの置き場所」は、アプリを公開するときに効きます。利用者のデータをどこで処理しているかは、プライバシーポリシーに書く必要があるからです。コードを読んでも分からないので、提供元の資料で確かめます。

  • テーブルを1つ作る。同時に権限も書く。後回しにしない。
  • ログインしていない状態でアクセスして、弾かれることを確かめる。
  • 自分のデータだけが見えることを、別のアカウントを作って確かめる。
  • 書き換えられて困る判定を洗い出し、サーバー側へ移す。
  • 変更をファイルとして残す仕組みを用意する。
使う前に把握しておきたい点
項目何が起きるか対応
RLSの書き忘れ誰でも読める状態になるテーブルを作ったら必ず設定する
権限の一括変更正規の利用者まで弾かれる対象を分けて、経路ごとに確認
クライアント側の判定書き換えで回避できるサーバー側で判定する
無料枠の上限止まる、または課金が必要になるデータ量と通信量を早めに見る
データの置き場所どの国で処理されるか委託先として確認が要る

表は左右にスクロールできます。

よくある疑問と、この記事で書いていないこと

Supabaseは個人開発に向いていますか?

普通のデータベース設計で表現できるアプリなら向いています。自分でサーバーを立てずに、データと認証とファイルを扱えます。逆に、データの形が毎日変わるうちは手間が勝ちました。

RLSは必ず設定しないといけませんか?

必要です。書き忘れると、誰でも全部読める状態になります。アプリから直接データベースを触る仕組みなので、誰が何を読めるかをデータベース側で決めることになります。テーブルを作ったら同時に書く、を習慣にしました。

RLSを厳しくすれば安全ですか?

なりません。私は緩い権限をまとめて締めて、本番の主要なデータが読めなくなりました。締めた対象の中に、権限の判定そのものが使っていた補助の関数が混じっていました。厳しくするのと壊すのは、途中まで同じ形をしています。

権限を変更する前に、何を確かめますか?

利用者が通る経路を全部です。同じデータでも、アプリからの直接読み取りと関数経由では通る境界が違います。加えて、拒否されるべき要求も動かします。許可の確認だけだと、開けすぎていても気づきません。

課金や回数制限の判定は、どこに置けばいいですか?

サーバー側です。アプリ側で数えると、入れ直せば戻ります。目安は単純で、そこを突破されて困るならサーバー側で判定します。表示の並び順のように困らないものは、アプリ側で構いません。

管理画面でテーブルを直すのは危ないですか?

直すこと自体は問題ありませんが、画面で直した変更は手元に残りません。あとから「なぜこの形なのか」が分からなくなります。変更をファイルとして残す仕組みを早めに用意するほうが困りません。私は途中からそうしました。

あとから別のサービスへ移せますか?

データそのものは普通のデータベースなので、持ち出し自体は難しくありません。重いのは認証まわりで、利用者のアカウントをどう引き継ぐかが残ります。始める前に一度考えておくと安心です。

プライバシーポリシーには何を書く必要がありますか?

利用者のデータをどこで処理しているかです。コードを読んでも分からないので、提供元の資料で確かめます。委託先として書くことになるため、公開の直前に慌てないよう先に調べておきます。

テーブルを作ったら権限を書く。権限を触ったら、通る経路と拒否される経路の両方を試す。この2つを習慣にしてから、同じ種類の事故は起きていません。確認の設計そのものはAIでテストケースを作る方法|正常系だけで終わらせない頼み方にまとめています。

この記事では、料金と無料枠の具体的な数字を書いていません。変わりやすいので、提供元の資料を見てもらうほうが確実です。私が見ているのはデータ量と通信量の二つで、増え方が読めるようになってから有料へ切り替えました。

ほかのサービスとの比較も書いていません。使っていないので並べて語れる立場にありません。書けたのは、任せた範囲の責任が自分に残るという一点です。サーバーを持たなくてよくなったぶん、権限とデータの置き場所は自分の設計になりました。そこだけは、代わりに決めてもらえません。

JOURNAL

KEEP READING
  1. 虫眼鏡の輪の外側に、いくつかの四角が取り残されている図PRODUCTサイトが検索に出ないときの確認手順。未登録12件を分解した検索に出ない原因を、載っていない場合と順位が低い場合に分けて確認する手順。Search Consoleの未登録12件を1件ずつ開き、直すべき2件を見つけた記録です。
  2. 二本の道が並び、途中で片方からもう片方へ細い橋が架かっている図PRODUCTFlutterとSwiftどちらを選ぶ?両方で作って分けた基準FlutterとSwiftUIの両方でアプリを作った立場から、出すOSと触る機能で選び分ける基準を整理。1つのアプリの中で混ぜた例と、どちらでも減らない作業も。
  3. 夜の机でノートパソコンに向かう人を後ろから見た図。「一人開発 × AI」の文字PRODUCT一人開発でAIを使うなら何から始める?5段階で試した活用法企画・実装・確認・調べもの・公開の5段階で、AIに任せた作業と自分で決めた作業を整理。一人でアプリとサイトを運営しながら試した範囲で書きます。
Journalへ戻る