【Next.js + Supabase】フロント側でのデータ取得SELECTはポリシーでfalseにした方がいいかもしれない?【意見募集】
PostgreSQL初心者のため、僕の認識が間違っているかもしれませんが、これはマズイのでは...?と感じてしまったので記事にしました。
皆さんのご意見を頂けると嬉しいです!
※内容としては個人開発ではありませんが、個人開発にも大きく影響しそうなので個人開発トピック使わせて頂きました。何卒!
何が問題なのか?
Supbabaseでフロント側でデータ取得をする場合、
import { createBrowserClient } from "@supabase/ssr";
...中略
const supabase = createBrowserClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!);
const { data } = await supabase.from('profiles').select("name, profile_image")
などで取得するかと思います。
これを実行すると、 https://【supabaseアカウント】.supabase.co/rest/v1/profiles?select=name,profile_image
にリクエストされます。
このURLから想像するに、 https://【supabaseアカウント】.supabase.co/rest/v1/profiles?select=*
とすると、 profilesのデータが全て取得できそうに思いませんか?
なんと、それができてしまうのです...。
問題を再現する
ChromeのNetworkタブからHeadersからApikeyをコピーします。
Postmanで先程のリクエスト先を入力し、headersにApikeyというキーとともに入れます。
たったこれだけで問題が再現できてしまいます。
※自分のサイトじゃないのにこんなにデータ取得できてしまっている...。
上記はとあるサイト(Supabaseのshowcasesにも掲載されているサイト)のデータです。特に、このサイトでは、登録者のメールアドレスはどこにも出力されていないのですが、メールアドレスを見れてしまう状態にありました。
Supabaseの仕様として1リクエストあたり1000件の取得に制限されているようなので、一度で全件取得とはいきませんが、offset値などを使って何度もリクエストすれば事実上、全てのデータを抜き出せてしまいます。
問題点を考える
今回はメールアドレスだったのでそれほど致命的ではありませんが、これが仮に住所データの場合は大問題になっていたことでしょう。
そもそもメールアドレスをpublicスキーマに露出させているのが問題なのかなと個人的に考えています。秘匿性の高いデータは、非公開のスキーマを作ってその中に格納するのが適切なのでしょう。
※スキーマの作成はGUIではできないので、SQL文を実行して作成する必要があります。
publicに置くデータは全て持っていかれても問題がないものに限定して置くべきかなと思います。
データ流出以外にも考慮したいのが「スクレイピング対策」です。
スクレイピングしやすさ100点すぎる
Supabaseで作られたサイトはスクレイピングのしやすさが半端ないことがお分かりいただけたかと思います。スクレイピング対策として一気に大量データを取得できない対策を考えるべきでしょう。
一生懸命に構築したデータベースのデータが秒でコピーされたら嫌ですよね...。
そこで対策として考えたのが下記です。
.rpc()
で行うべき?
【対策案】フロント側でSELECTするリクエストはポリシーで全て弾き、データ取得は 対策を考えた結果、この方法になるのかなと思います。
ポリシーでSELECTのリクエストを全て拒否(false)にしてしまうのが一番安全なのかなと現時点では落ち着いています。PostgreSQLで関数を作り、 .rpc()
で実行して取得するという方法です。
これであれば攻撃者の任意のSELECT文で動かせないので比較的に安全になるのではないでしょうか。プロジェクトの開発者だけが制御できる状態にしておくべきなんだと思います。
2023-10-14追記-->
解決っぽい道が見えてきたので記事書きました!
<--追記終了
皆さんのご意見を聞きたいです!
どんな些細な内容でも構いません。
皆さんのご意見をお聞かせ頂きたいです!
"そもそも君が感じてる問題点おかしいよ?" という根本的な指摘もお待ちしています!
※慎重になりすぎて個人開発が完成しないんご...。
Discussion