FixVibe

// docs / baas security / supabase rls scanner

Сканер Supabase RLS: знайдіть таблиці з відсутньою або зламаною безпекою на рівні рядків

Безпека на рівні рядків (RLS) — це єдине, що стоїть між даними ваших клієнтів та інтернетом, коли ви випускаєте застосунок на базі Supabase. ШІ-інструменти кодування генерують код у формі RLS, який компілюється, випускається та тихо зливає дані — таблиці, створені без увімкненого RLS, політики, які читають, але ніколи не обмежують, предикати, що порівнюють стовпець із самим собою. Ця стаття показує, що сканер Supabase RLS може довести ззовні, чотири форми зламаного RLS, які з'являються у vibe-кодованих застосунках, і як просканувати ваше власне розгортання менш ніж за хвилину.

Що може довести зовнішнє сканування RLS

Пасивне сканування RLS виконується проти кінцевої точки PostgREST, яку Supabase надає за адресою https://[project].supabase.co/rest/v1/. Воно використовує лише публікований ключ anon — той самий ключ, який використовує ваш браузер — і зондує метадані переліку таблиць, анонімні читання та анонімні записи. Воно ніколи не автентифікується як користувач і ніколи не торкається привілеїв сервісної ролі. Усе, що воно може робити, може робити неавторизований зловмисник в інтернеті.

Ззовні бази даних сканер може підтвердити наступне з високою впевненістю:

  • RLS вимкнено на таблиці. PostgREST повертає рядки для анонімного SELECT, коли RLS вимкнено або коли політика це дозволяє. Будь-який випадок — це знахідка.
  • Анонімна роль може перелічувати таблиці. GET /rest/v1/ із ключем anon повертає схему OpenAPI для кожної таблиці, до якої роль anon має будь-які привілеї. ШІ-згенеровані застосунки часто надають USAGE для схеми та SELECT для кожної таблиці, що оголює повну карту схеми навіть тоді, коли RLS відхиляє фактичні читання.
  • Анонімна роль може вставляти. Зондуючий POST із припущенням про форму стовпців буде успішним, якщо в RLS немає політики INSERT, яка це відхиляє — навіть якщо SELECT заблоковано.
  • Ключ сервісної ролі знаходиться у браузерному бандлі. Суміжно з RLS: якщо сканер знаходить SUPABASE_SERVICE_ROLE_KEY або будь-який JWT із role: service_role у JavaScript-бандлі, RLS стає беззмістовним — власник цього ключа обходить кожну політику.

Що зовнішнє сканування не може довести

Будьте чесними щодо меж сканера. Зовнішнє сканування RLS не може прочитати вашу таблицю pg_policies, ваші файли міграцій або точний предикат будь-якої політики. Воно робить висновки з поведінки чорної скриньки, що означає, що іноді воно повідомить про знахідку, яка виявиться навмисно публічними даними (таблиця маркетингової розсилки, публічний каталог продуктів). Звіт FixVibe позначає їх як середній рівень довіри, коли сканер не може розрізнити наміри — перегляньте назву таблиці та ухваліть рішення.

Чотири форми зламаного RLS, які створюють ШІ-інструменти

Коли ви спрямовуєте Cursor, Claude Code, Lovable або Bolt на Supabase, у тисячах застосунків виникають одні й ті ж чотири шаблони зламаного RLS. Кожен проходить перевірку типів, компілюється та випускається:

Форма 1: RLS ніколи не вмикалося

Найпоширеніший режим відмови. Міграція створює таблицю, але розробник (або ШІ-інструмент) забуває ALTER TABLE ... ENABLE ROW LEVEL SECURITY. PostgREST охоче обслуговує всю таблицю будь-кому, хто має ключ anon. Виправлення: ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY; ALTER TABLE public.[name] FORCE ROW LEVEL SECURITY;. FORCE не є необов'язковим — без нього власник таблиці (і будь-яка роль із володінням таблицею) обходить RLS.

sql
ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.[name] FORCE  ROW LEVEL SECURITY;

Форма 2: RLS увімкнено, немає політик

Тонша відмова. RLS увімкнено, але політики не написано. За замовчуванням у PostgreSQL — відхиляти, тож автентифіковані користувачі нічого не бачать — і розробник додає USING (true), щоб застосунок працював, що дозволяє всім читати все. Виправлення: напишіть політику з обмеженням через auth.uid(): CREATE POLICY "select_own" ON public.[name] FOR SELECT USING (auth.uid() = user_id); та відповідну політику INSERT/UPDATE/DELETE.

sql
CREATE POLICY "select_own"
  ON public.[name]
  FOR SELECT
  USING (auth.uid() = user_id);

Форма 3: Політика порівнює стовпець із самим собою

A copy-paste artefact. The developer writes <code>USING (user_id = user_id)</code> — which is always true — instead of <code>USING (auth.uid() = user_id)</code>. Type-checks pass; the policy permits every row. <strong>Fix:</strong> always compare a column to a function call (<code>auth.uid()</code>, <code>auth.jwt()->>'org_id'</code>, etc.), never to itself or to a constant.

Форма 4: Політика на SELECT, але не на INSERT/UPDATE

Розробник блокує читання, але забуває записи. Політики RLS працюють покомандно. FOR SELECT захищає лише читання; анонімний клієнт усе ще може зробити INSERT, якщо жодна політика цього не відхиляє. Виправлення: створіть політику для кожної команди або використовуйте FOR ALL із явними реченнями USING та WITH CHECK.

Як працює сканер FixVibe Supabase RLS

Перевірка baas.supabase-rls виконується у три етапи, кожен із явними рівнями довіри:

  1. Етап 1 — зняття відбитків. Сканер обходить розгорнутий застосунок, розбирає його JavaScript-бандл і витягає URL проєкту Supabase та ключ anon із конфігурації часу виконання. Жодних здогадок щодо DNS, жодного перебору — він читає те, що читає браузер.
  2. Етап 2 — виявлення схеми. Один GET /rest/v1/ із ключем anon повертає схему OpenAPI для кожної таблиці, яку може бачити роль anon. Сканер записує імена таблиць, але не читає дані рядків на цьому етапі.
  3. Етап 3 — зонди читання та запису. Для кожної виявленої таблиці сканер виконує один анонімний SELECT із limit=1. Якщо повертаються рядки, RLS дозволяє. Сканер на цьому зупиняється — він не перелічує рядки, не розбиває на сторінки, не змінює дані. Зонди INSERT захищені підтвердженим володінням доменом та явною згодою; вони ніколи не запускаються проти неперевірених цілей.

Кожна знахідка постачається з точним URL запиту, статусом відповіді, формою відповіді (лише заголовки) та ім'ям таблиці. Підказка виправлення від ШІ внизу знахідки — це копійований блок SQL, який ви запускаєте в редакторі SQL Supabase.

Що робити, коли сканер щось знаходить

Кожна знахідка RLS — це аварійна ситуація часу виконання. Публічні кінцеві точки PostgREST скануються зловмисниками за хвилини. Послідовність виправлення механічна:

  1. Перевірте кожну таблицю. Запустіть SELECT schemaname, tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public'; у редакторі SQL Supabase. Будь-який рядок із rowsecurity = false — це проблема.
  2. Увімкніть RLS на кожній публічній таблиці. За замовчуванням ставте ENABLE ROW LEVEL SECURITY та FORCE ROW LEVEL SECURITY на кожну створену таблицю — зробіть це шаблоном міграції.
  3. Створюйте політики покомандно. Не використовуйте FOR ALL USING (true). Пишіть явні політики для SELECT, INSERT, UPDATE, DELETE — кожна обмежена через auth.uid() або стовпець org-id з auth.jwt().
  4. Перевірте за допомогою другого облікового запису. Зареєструйтеся як інший користувач, спробуйте прочитати записи іншого користувача через REST API напряму. Якщо відповідь — 200, політика зламана.
  5. Повторне сканування. Після застосування виправлення повторно запустіть сканування FixVibe проти того ж URL. Знахідка baas.supabase-rls має зникнути.
sql
-- Audit every table for missing RLS. Run in the Supabase SQL editor.
SELECT schemaname, tablename, rowsecurity
FROM   pg_tables
WHERE  schemaname = 'public'
ORDER  BY rowsecurity, tablename;

Як це порівнюється з іншими сканерами

Більшість загальних DAST-інструментів (Burp Suite, OWASP ZAP, Nessus) не знають, що таке PostgREST. Вони обходитимуть ваш застосунок, ігноруватимуть шлях /rest/v1/ та звітуватимуть про HTML-сторінки, які вони розуміють. Snyk і Semgrep — це інструменти статичного аналізу — вони знаходять файли міграцій у вашому репозиторії з відсутніми викликами RLS, але не можуть довести, що розгорнута база даних неправильно налаштована. FixVibe займає цю прогалину: пасивний, BaaS-обізнаний, зосереджений на тому, що неавторизований зловмисник може довести з публічного URL.

Поширені запитання

Чи буде сканер читати або змінювати мої дані?

Ні. Пасивні сканування виконують щонайбільше один SELECT ... limit=1 на виявлену таблицю, щоб підтвердити, чи дозволяє RLS анонімні читання. Сканер записує форму відповіді, а не вміст рядків. Зонди INSERT, UPDATE та DELETE захищені підтвердженим володінням доменом і ніколи не запускаються проти неперевірених цілей.

Чи працює це, якщо мій проєкт Supabase призупинено або на користувацькому домені?

Призупинені проєкти повертають 503 на кожен запит — сканер звітує про проєкт як недосяжний. Користувацькі домени працюють, доки розгорнутий застосунок усе ще завантажує клієнтський SDK Supabase у браузері; сканер витягає URL проєкту з бандла в будь-якому випадку.

Що, якщо мій ключ anon ротується або мій публікований ключ змінюється?

Запустіть сканування повторно. Сканер повторно витягає ключ із поточного бандла під час кожного запуску. Ротація знеціняє лише попередній звіт, а не стан політик бази даних.

Чи перевіряє сканер нову модель публікованих ключів Supabase (<code>sb_publishable_*</code>)?

Так. Детектор розпізнає як застарілі anon JWT, так і новіші ключі sb_publishable_* і трактує їх однаково — обидва призначені бути публічними та обидва залишають RLS єдиною лінією оборони.

Наступні кроки

Запустіть безкоштовне сканування FixVibe проти вашого продакшен-URL — перевірка baas.supabase-rls увімкнена на кожному тарифі, включно з безкоштовним. Для глибшого розгляду того, що ще може витекти з проєкту Supabase, дивіться Сервісний ключ Supabase, розкритий у JavaScript та Чек-лист безпеки сховищ Supabase. Для оглядового погляду на всіх постачальників BaaS читайте Сканер неправильних налаштувань BaaS.

// скануйте вашу baas-поверхню

Знайдіть відкриту таблицю раніше, ніж це зробить хтось інший.

Введіть продакшен-URL. FixVibe перелічить постачальників BaaS, з якими взаємодіє ваш застосунок, зніме відбитки з їхніх публічних кінцевих точок і повідомить, що неавторизований клієнт може прочитати або записати. Безкоштовно, без встановлення, без картки.

  • Безкоштовний тариф — 3 сканування на місяць, без картки під час реєстрації.
  • Пасивне зняття відбитків BaaS — не потрібна перевірка володіння доменом.
  • Supabase, Firebase, Clerk, Auth0, Appwrite та інші.
  • Підказки виправлення від ШІ для кожної знахідки — вставте назад у Cursor / Claude Code.
Сканер Supabase RLS: знайдіть таблиці з відсутньою або зламаною безпекою на рівні рядків — Docs · FixVibe