3

WebTech

Личный кабинет

Проекты, коммерческие предложения, документы и отчёты — в одном месте.

Войти Зарегистрироваться Забыли пароль?
Изоляция данных и соответствие требованиям

Данные клиентов не пересекаются ни в коде, ни в СУБД

Строим изоляцию данных так, чтобы она не зависела от внимательности разработчика: политики RLS в базе, обязательный tenant-контекст в приложении, шифрование полей ключами тенанта и аудит каждого доступа.

Или сразу: +7 (962) 368-39-51 Telegram

RLS
политики доступа внутри PostgreSQL
2
рубежа: приложение и сама СУБД
KEK
и ключ шифрования на каждого тенанта
152-ФЗ
GDPR, аудит и удаление по запросу
Задачи

Как данные утекают между тенантами

Механизмы утечки почти всегда одни и те же, и почти никогда они не связаны со взломом извне.

Изоляция держится на фильтре в коде

Отчёт, экспорт или админ-скрипт забыл условие по tenant_id — и выборка вернула строки чужого клиента.

RLS включён формально

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

Утечка через кэш, поиск и логи

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

Персональные данные лежат открыто

Паспорт, телефон и адрес хранятся в plaintext, один ключ шифрования на всю систему, ротации нет — дамп базы равен утечке.

Нет аудита доступа к данным

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

Удаление по запросу делают вручную

Право на удаление и экспорт выполняются SQL-скриптом по памяти: часть данных остаётся в архивах, кэше и бэкапах.

Решения

Как мы делаем изоляцию данных

Изоляция проектируется как защита в глубину: ошибка в одном слое не должна открывать данные другого тенанта.

RLS и политики доступа

Переносим правило «вижу только своё» внутрь СУБД, где его нельзя забыть в новом запросе.

  • ENABLE и FORCE ROW LEVEL SECURITY для всех таблиц тенанта
  • Политики USING и WITH CHECK по текущему тенанту
  • Роль приложения без BYPASSRLS и без владения таблицами
  • Контекст тенанта в транзакции, а не в сессии пула

Второй рубеж в приложении

Приложение не доверяет себе: контекст обязателен, а запросы вне репозиториев запрещены соглашениями и проверками.

  • Глобальная область видимости и явный tenant-контекст
  • Отдельный слой доступа к данным вместо сырых запросов
  • Представления и функции с фильтром по тенанту
  • Проверка в CI: новая таблица без политики не проходит сборку

Шифрование полей и ключей

Персональные данные шифруются на уровне модели, ключ у каждого тенанта свой, а мастер-ключ живёт в KMS.

  • Конвертное шифрование: мастер-ключ и ключ данных тенанта
  • Шифрование PII в колонках и в файловом хранилище
  • Детерминированный хеш для поиска по зашифрованному полю
  • Ротация ключей и криптографическое удаление тенанта

Аудит, тесты и соответствие

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

  • Журнал доступа: кто, что, когда, из какого тенанта
  • Append-only хранение и выгрузка журнала во внешний контур
  • Тесты: запрос из чужого контекста возвращает ноль строк
  • 152-ФЗ: локализация и согласия; GDPR: экспорт и удаление
Процесс

Как мы внедряем изоляцию данных

Начинаем с инвентаризации данных и требований регуляторов, затем строим политики и только потом трогаем код продукта.

  1. 01 1–2 недели

    Классификация данных и модель доступа

    Составляем карту данных по тенантам, помечаем персональные и чувствительные поля, фиксируем роли и требования 152-ФЗ и GDPR.

  2. 02 2–3 недели

    Проектирование политик и ключей

    Описываем политики RLS, схему tenant-контекста, иерархию ключей шифрования, формат журнала аудита и негативные тесты.

  3. 03 6–12 недель

    Внедрение и миграция

    Включаем RLS и разделяемые роли, переводим доступ к данным в единый слой, шифруем существующие поля без простоя.

  4. 04 2–3 недели

    Негативные тесты и аудит

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

Почему фильтр по tenant_id в коде — это не изоляция

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

Поэтому правило «вижу только своё» мы переносим внутрь СУБД через row-level security. Политики проверяются на каждой строке независимо от того, каким способом построен запрос, и включены принудительно, в том числе для владельца таблицы. Роль приложения не имеет права обходить политики, а контекст тенанта устанавливается в начале транзакции, чтобы он не «переехал» между запросами в общем пуле соединений.

Персональные данные: шифрование, аудит и удаление

Изоляция тенантов не отменяет требования к персональным данным. Мы классифицируем поля и шифруем чувствительные значения на уровне модели, используя конвертное шифрование: у каждого тенанта свой ключ данных, а мастер-ключ хранится в KMS и никогда не попадает в базу. Для поиска по зашифрованному полю используется детерминированный хеш, поэтому фильтры и уникальные индексы продолжают работать.

  • журнал доступа к персональным данным: субъект, объект, действие, время, тенант;
  • негативные тесты изоляции в CI: чужой контекст даёт ноль строк;
  • экспорт данных тенанта и субъекта в машиночитаемом виде;
  • удаление по запросу с подтверждением по всем хранилищам и кэшу;
  • ротация ключей и криптографическое удаление вместо физического.

Такой контур закрывает и 152-ФЗ, и GDPR: видно, где лежат данные, кто к ним обращался и как выполнено требование об удалении.

Частые вопросы

Нет, это только один рубеж. Фильтр в коде легко забыть в новом отчёте, экспорте или фоновой задаче, и ошибка не проявится на тестах с одним тенантом. Поэтому мы дублируем правило внутри СУБД политиками row-level security, включёнными принудительно, и дополнительно запрещаем сырые запросы вне слоя доступа к данным.

Контекст тенанта устанавливается в начале транзакции и сбрасывается при её завершении, поэтому соединение из пула не переносит чужой контекст в следующий запрос. Роль приложения не должна иметь права обходить политики и не должна владеть таблицами. Если соединения кэшируются на уровне воркеров, контекст задаётся заново для каждой единицы работы.

Мы используем конвертное шифрование: у каждого тенанта свой ключ данных, зашифрованный мастер-ключом из KMS. Это разграничивает доступ и упрощает ротацию. При уходе клиента достаточно уничтожить его ключ данных — зашифрованные значения остаются нечитаемыми, что и называют криптографическим удалением, а физическая очистка бэкапов идёт по политике хранения.

Мы заранее описываем карту данных тенанта и субъекта, включая кэш, поисковый индекс, файловое хранилище и очереди. На её основе строятся процедуры экспорта в машиночитаемом виде и удаления с подтверждением по каждому хранилищу. Журнал аудита фиксирует обращения к персональным данным, поэтому факт и объём обработки можно подтвердить документально.

Технические основы: другие темы

Смежные технические темы, с которыми эта задача обычно решается в одном проекте.

Проверим, изолированы ли ваши данные

Разберём текущие политики доступа и шифрование, покажем слабые места и предложим план устранения без остановки продукта.