Как это работает · Урок 4 из 4Средний уровень · 5 мин чтения
Кто что видит: почему правила доступа должны жить в базе данных
Спрятать кнопку — не значит защитить. Попробуйте сами проникнуть в закрытую систему и посмотрите, как правила в базе данных берегут данные.
🎯 Из этого урока вы узнаете
- чем спрятанная кнопка отличается от настоящей защиты данных
- что такое «роли» — посетитель, участник, редактор, администратор
- как база данных может отказать в запросе, кто бы его ни прислал
- почему ссылки на скачивание, которые сгорают через 60 секунд, безопаснее
- три вопроса, которые стоит задать любому разработчику, прежде чем доверить ему данные
Содержание
Представьте школу. На двери учительской висит табличка: «Только для учителей». Большинство учеников её уважают. Но дверь не заперта. Один любопытный ученик, который не обратит внимания на табличку, может войти и прочитать экзаменационные билеты.
Многие сайты защищают данные именно так: табличкой, а не замком. Этот урок показывает разницу — и даёт вам самим попробовать пройти в эту дверь.
Пример — Kamarob, платформа, которую я сделал для некоммерческих организаций: публичный сайт, аккаунты участников, внутренние новости и документы, командный чат и админ-панель.
Вопрос, который важен
Когда организация хранит онлайн данные участников, внутренние документы или закрытые чаты, важный вопрос — не «могут ли люди войти?». А вот какой:
Что именно каждый человек может читать и менять?
Чтобы ответить, каждому человеку дают роль:
- Посетитель — не вошёл. Читает публичные новости, может написать через форму обратной связи.
- Участник — вошёл. Ещё читает новости и документы для участников, пользуется чатом.
- Редактор — ещё пишет новости и загружает документы.
- Администратор — ещё управляет участниками и ролями, читает письма из формы обратной связи.
Пока всё хорошо. Настоящий вопрос — где живут эти правила.
Табличка на двери: правила только в приложении
Самый простой способ — положить правила в приложение. Участник не видит кнопку «Удалить». Посетитель не видит ссылку «Входящие». Выглядит безопасно.
Но приложение — лишь один из путей к данным. За каждым сайтом стоят сервер и база данных, и приложение общается с ними запросами — такими же, какие вы видели в уроке 1. Любой, кто умеет, может отправить эти запросы напрямую — без приложения, без кнопок. Часто ключ для таких запросов даже лежит внутри самой веб-страницы, потому что он нужен браузеру.
Если в самой базе нет правил, она ответит любому с этим ключом. Спрятанная кнопка была просто табличкой на незапертой двери.
Попробуйте проникнуть
Выберите, кто вы и что хотите сделать. Сначала нажмите Через приложение. Потом — Отправить запрос прямо в базу. Потом перенесите правила в базу данных и попробуйте снова.
Попробуйте
Кто что может
Получилось у посетителя прочитать документ для участников, когда правила были только в приложении? Так и происходят настоящие утечки: никто не «взламывал» ничего хитрого — просто спросили базу напрямую, и она ответила.
Замок на двери: Row Level Security
База данных, которую использует Kamarob, — Postgres — умеет прикреплять правило к каждой таблице: прежде чем показать или изменить строку, проверь, кто спрашивает. Это называется Row Level Security — RLS, правила для каждой строки.
Если правило говорит «нет», база отказывает. Неважно, какой экран, скрипт или запрос спрашивает. Приложение по-прежнему прячет кнопки — это удобно людям, — но данные бережёт уже не оно.
Как выглядят правила
Вот несколько настоящих правил Kamarob, немного упрощённых. Их можно читать почти как английский текст:
-- Опубликованные публичные посты видят все; участники видят ещё и посты для участников.
create policy "posts: published for their audience" on posts for select
using (status = 'published' and (visibility = 'public' or is_member()));
-- Писать посты могут только редакторы и администраторы.
create policy "posts: editors write" on posts for insert with check (can_edit());
-- Письма из формы обратной связи читают только администраторы.
create policy "contact: admins read" on contact_messages for select using (is_admin());
-- Человек может менять только своё имя и язык, но никогда — свою роль.
revoke update on profiles from authenticated;
grant update (full_name, locale) on profiles to authenticated;Последние две строки стоит рассмотреть внимательнее. Даже вошедший человек, отправляя запрос напрямую, не может изменить свою роль — база просто не разрешает менять этот столбец. Роли меняются только через одну специальную функцию, которая сначала проверяет, что её вызывает администратор.
Ссылки, которые сгорают
Документы для участников — отчёты, планы, договоры — это файлы. Файлы обычно скачивают по ссылке. Но ссылку можно переслать: участник копирует её в общий чат, и теперь любой со ссылкой может скачать файл. Навсегда.
Поэтому Kamarob выдаёт подписанные ссылки, которые работают всего 60 секунд. Участник нажимает «Скачать», сервер проверяет, что он участник, создаёт свежую ссылку, и браузер сразу ею пользуется. Если кто-то перешлёт эту ссылку, к моменту, когда её откроют, она уже мертва.
Попробуйте
Ссылка, которая сгорает
Документы для участников скачиваются по ссылке, которая работает 60 секунд.
Проверяйте правила, а не только экраны
Непроверяемые правила постепенно «уплывают»: кто-то добавил таблицу и забыл её правило или поменял функцию и открыл дыру. Поэтому у Kamarob есть отдельный набор тестов, которые входят под разными людьми в настоящую базу и проверяют, что каждый может и чего не может. Например:
- посетитель не может читать профили, чат и входящие;
- демо-администратор может открыть админ-панель, но любое изменение ему запрещено;
- демо-администратор видит только примерных людей и сообщения, никогда — данные настоящих посетителей;
- никто не может скачать файл для участников, не войдя в систему.
Эти тесты запускаются перед каждым выпуском. Если правило сломалось, выпуск останавливается.
Демо-администратор: показать без риска
На главной странице Kamarob есть публичный демо-вход в админ-панель, чтобы любой мог посмотреть, как она работает. Звучит опасно — но с правилами в базе это безопасно: демо-роль может смотреть админ-панель, видит только придуманные примеры, и любую попытку что-то изменить отклоняет сама база данных. Те же правила, что берегут данные, позволяют открыто показывать систему.
Организациям, которые выбирают систему
Прежде чем доверить разработчику — или готовой платформе — данные ваших участников, задайте три вопроса:
- Где проверяются правила доступа? Хороший ответ: в базе данных (или на сервере), а не только в приложении.
- Они проверяются тестами? Хороший ответ: да, автоматически, перед каждым выпуском, под разными ролями.
- Что будет, если отправить запросы без приложения? Хороший ответ: ровно то же, что через приложение, — отказ там, где нельзя.
Если на первый вопрос отвечают «в приложении» — ваши данные в одном любопытном ученике от утечки.
Проверьте себя
Попробуйте
Проверьте себя
1. Участник не видит кнопку «Входящие». Защищает ли это входящие?
2. Правила только в приложении, и посетитель отправляет запрос прямо в базу. Что будет?
3. Что делает Row Level Security?
4. Почему ссылка на скачивание работает только 60 секунд?
5. Может ли вошедший участник сделать себя администратором, отправив запрос напрямую?
Маленький словарь
- Роль — набор прав: посетитель, участник, редактор, администратор.
- Запрос — сообщение, которое программа отправляет серверу или базе, чтобы получить данные или что-то изменить.
- Row Level Security (RLS) — правила в базе данных, которые построчно решают, кто что может видеть и менять.
- Политика (policy) — одно такое правило.
- Подписанная ссылка — ссылка на скачивание, которая несёт доказательство права и быстро сгорает.
- Демо-аккаунт — публичный вход, который может смотреть, но ничего не может менять.
- Утечка данных — когда информация попадает к тем, кому не должна.
Берегите данные ваших участников
Я делаю платформы для организаций — новости, документы, чат, админ-панель — с правилами доступа в базе данных и тестами для каждой роли, на таджикском, русском и английском. Попробуйте демо: на главной странице kamarob.simorgh-dev.workers.dev есть вход в админ-панель только для просмотра. Вопросы: @SimorghDev.