Перейти к содержимому
PD
Supabase

Авторизация и RLS в Supabase: роли и доступ

Как устроена авторизация, что такое политики доступа на уровне строк, какие политики нужны в типовом проекте и где чаще всего ломаются MVP.

Все статьи гида Supabase · 7

Это главная статья гида: вся модель безопасности Supabase держится на правилах доступа к строкам. Проект, где они настроены неверно, выглядит рабочим и таковым не является.

Как устроена авторизация

Пользователь регистрируется или входит, сервис выдаёт ему токен. Приложение отправляет этот токен с каждым запросом, а база по нему понимает, кто именно спрашивает.

Ключевая деталь, которую надо понять сразу: запросы идут в базу напрямую из приложения. Промежуточного слоя, который проверял бы права, нет - его роль выполняют правила в самой базе.

Отсюда два ключа:

  • Публичный ключ используется в приложении и по определению доступен любому пользователю. Он не даёт никаких прав сам по себе: права определяются токеном и политиками.
  • Служебный ключ обходит все правила. Он должен жить только на сервере и никогда не попадать в клиентский код. Утечка такого ключа означает полный доступ ко всем данным.

Что такое RLS

Row Level Security - механизм PostgreSQL, ограничивающий доступ на уровне отдельных строк.

Вместо проверки в коде приложения вы описываете правило один раз в базе: «пользователь видит только те заказы, где идентификатор владельца совпадает с его собственным». Правило действует для любого запроса, откуда бы он ни пришёл.

Два обязательных условия, и оба пропускают:

  1. Построчный доступ включён для таблицы. Без этого таблица открыта всем.
  2. Написаны политики. Таблица с включённым RLS и без политик закрыта полностью, что честнее, но тоже неверно.

Типовые политики

Набор, покрывающий большинство проектов:

Своё видно, чужое нет. Пользователь читает и меняет строки, где он владелец.

Общее чтение, ограниченная запись. Каталог виден всем, менять может только владелец записи.

Разделение чтения и записи. Отдельные политики на чтение, вставку, обновление и удаление. Частая ошибка - одна политика на всё: пользователь получает право менять то, что должен был только читать.

Роли. Признак роли хранится в базе, а не в токене, который пользователь может подделать. Политика проверяет роль запросом к таблице пользователей.

Мягкое удаление вместо настоящего. Запись помечается удалённой, а политика скрывает помеченные. Дешевле, чем восстанавливать удалённое.

Где чаще всего ломаются MVP

Пять ошибок в порядке частоты:

1. RLS не включён. Таблица создана, данные добавлены, всё работает. Работает потому, что доступ открыт всем, у кого есть публичный ключ. Это самая частая и самая дорогая ошибка.

2. Служебный ключ в клиентском коде. Обходит все правила. Ключ в коде фронтенда виден всем.

3. Проверка прав только в интерфейсе. Кнопка удаления скрыта, а запрос на удаление проходит: пользователь может отправить его напрямую.

4. Слишком широкая политика. Разрешение на чтение всей таблицы «на время отладки», которое остаётся навсегда.

5. Роль из токена. Токен формируется на клиенте и не является доказательством. Роль проверяется по данным в базе.

Как проверить, что всё закрыто

Проверять надо специально, а не по факту работы приложения:

  1. Список таблиц с выключенным RLS. Одним запросом. Каждая такая таблица - потенциальная утечка.
  2. Запрос от имени другого пользователя. Заведите второй аккаунт и попробуйте прочитать чужие данные напрямую, минуя интерфейс.
  3. Запрос без токена вовсе. Что видно анонимному пользователю с публичным ключом.
  4. Попытка изменения чужой строки.
  5. Поиск служебного ключа в клиентском коде и в репозитории.

Практическое правило: включайте RLS сразу при создании таблицы, до того, как положите в неё данные. Возвращаться к этому потом означает проверять каждую таблицу вручную, а какую-то вы пропустите.

Логика, которую нельзя отдавать клиенту, живёт в edge-функциях. Общая картина - гид по Supabase.

Вопросы и ответы

Что такое RLS в Supabase?

Механизм PostgreSQL, ограничивающий доступ на уровне отдельных строк таблицы. Вместо проверки прав в коде приложения правило описывается один раз в базе, и оно действует для любого запроса, откуда бы он ни пришёл. Это и есть основа модели безопасности здесь.

Почему в Supabase видны чужие данные?

Почти всегда потому, что для таблицы не включён построчный доступ или не написаны политики. Таблица без включённого RLS доступна всем, у кого есть публичный ключ, а он по определению есть у любого пользователя приложения. Это ошибка номер один в проектах на Supabase.

Можно ли доверять проверкам на клиенте?

Нет. Всё, что выполняется в браузере, находится под контролем пользователя: запрос можно отправить напрямую, минуя ваш интерфейс. Клиентские проверки нужны для удобства, а безопасность обеспечивается только правилами в базе.

Ещё по теме