Опирается на правила: PG-AN-001PG-AN-072 из PostgreSQL Style Guide → раздел Дамп прода для разработчика — анонимизация.

Важно знать

  • Никогда не передавай прод-дамп без анонимизации (GDPR / 152-ФЗ).
  • Default — синтетический dataset через faker.
  • PII: email, phone, ФИО, адрес, паспорт, ИНН, дата рождения, IP, карта.
  • Косвенные: геолокация, уникальные комбинации, User-Agent.
  • Стратегии: удаление, замена константой, псевдонимизация (md5), faker, shuffle, generalization.
  • Email — псевдонимизация через md5 (уникальность сохранилась).
  • Полный сценарий: copy prod → anonymizer SQL → dump → передача → удалить anonymizer-БД.
  • Скрипт анонимизации в репо, версионируется.
  • Re-identification через комбинацию полей — реальная угроза.
  • k-anonymity или generalization идентификаторов.

Прод содержит PII. Передача без анонимизации = нарушение закона.

Базовая позиция

PG-AN-001..003:

Никогда не передавай прод-дамп без анонимизации, даже «надёжному» разработчику:

  • Юридически — нарушение закона о персональных данных.
  • Безопасно — каждая копия = новая поверхность атаки.
  • Этически — пользователи не подписывались.

Default для разработчика — синтетический dataset через faker. Покрывает большинство кейсов.

Реальный дамп для воспроизведения проблемы:

  • Анонимизация PII.
  • Минимальный объём (одна сущность, не вся БД).
  • DPA (Data Processing Agreement) или внутренний регламент.

Что считается PII

PG-AN-010..012:

Прямые идентификаторы:

  • Имя, фамилия, отчество.
  • Email, телефон, адрес.
  • Паспорт, СНИЛС, ИНН, ВУ.
  • Дата рождения.
  • IP-адрес.
  • Номер банковской карты, счёта.

Косвенные:

  • Геолокация (точнее населённого пункта).
  • Уникальные комбинации (профессия + город + возраст).
  • User-Agent / fingerprint.
  • Связи в графе пользователей.

Бизнес-секреты (не PII, но чувствительно):

  • B2B-цены.
  • Внутренние комментарии модераторов.
  • Логи действий сотрудников.

Стратегии

PG-AN-020:

СтратегияЧтоКогда
УдалениеSET email = NULLПоле не нужно для дебага
Замена константойemail = 'masked@example.com'Тестируем структуру
Псевдонимизация'user' || md5(email) || '@test'Уникальность, обратимости нет
Faker-заменаслучайное имя/emailРеалистичный dataset
Shuffleпереставить значения между строкамиРаспределение, потеря связи
Generalizationвозраст → группаСнижение точности для аналитики
ХэшированиеSHA-256 от emailТолько как opaque ID

Маскирование полей

PG-AN-030..034:

Email — псевдонимизация

UPDATE customer
SET email = 'user' || substring(md5(email), 1, 8) || '@example.test'
WHERE email IS NOT NULL;

Уникальность сохранилась (одинаковый email → одинаковый псевдоним). Восстановить нельзя.

Телефон — формат с шумом

UPDATE customer
SET phone = '+7000' || lpad((random() * 10000000)::int::text, 7, '0')
WHERE phone IS NOT NULL;

Имя — faker

Через postgresql_anonymizer:

CREATE EXTENSION anon CASCADE;
SELECT anon.init();

UPDATE customer SET
    first_name = anon.fake_first_name(),
    last_name  = anon.fake_last_name();

Без extension — Java/Python faker (faker.js, Faker).

Дата рождения — generalize

UPDATE customer SET born_on = date_trunc('year', born_on)::date;

Возраст ±год сохранён, конкретный день — нет.

Адрес — только город

UPDATE customer SET
    address = NULL,
    apartment = NULL;

Полный сценарий

PG-AN-040..041:

# 1. копия прод в staging-anonymizer
pg_dump prod | psql anonymizer
-- 2. анонимизация в одной транзакции
BEGIN;

UPDATE customer SET
    email = 'user' || substring(md5(email), 1, 8) || '@example.test',
    phone = '+7000' || lpad((random()*10000000)::int::text, 7, '0'),
    first_name = 'Имя' || id,
    last_name  = 'Фамилия' || id;

UPDATE customer_address SET
    street = NULL,
    building = NULL,
    apartment = NULL;

UPDATE customer_document SET
    number = '0000' || lpad(id::text, 6, '0'),
    issued_by = 'TEST';

UPDATE payment SET
    card_last4 = '0000',
    card_holder_name = 'TEST';

DELETE FROM audit_log WHERE created_at < now() - interval '7 days';

COMMIT;
# 3. дамп анонимизированной
pg_dump anonymizer -Fc > prod-anon-$(date +%F).dump

# 4. передача

# 5. удалить anonymizer-БД (не оставляй полу-обработанные данные)
dropdb anonymizer

Скрипт хранится в репо, версионируется, ревьюется. Не однострочник «по памяти».

postgresql_anonymizer

PG-AN-050..051: специализированное расширение.

Возможности:

  • Декларативные правила: «колонка email → fake email».
  • Динамическое маскирование (вид для определённых ролей).
  • Готовые функции: anon.fake_first_name(), anon.fake_email(), anon.partial(text, 2, '*****', 2).
CREATE EXTENSION anon CASCADE;
SELECT anon.init();

SECURITY LABEL FOR anon ON COLUMN customer.email
    IS 'MASKED WITH FUNCTION anon.fake_email()';

SECURITY LABEL FOR anon ON COLUMN customer.last_name
    IS 'MASKED WITH FUNCTION anon.fake_last_name()';

-- маскированный дамп
SELECT anon.dump('customer');

Альтернативы: Greenmask, ARX, ad-hoc-скрипты.

Что нельзя замаскировать

PG-AN-060..062:

Оставлять как есть:

  • customer.id, order.id — связи между таблицами должны работать.
  • Технические FK.

Бизнес-данные не PII:

  • Названия продуктов, цены — сохраняем.
  • Статусы, типы — сохраняем.

Free-text поля (комментарии, описания) — сложный случай. Пользователь мог вписать email, телефон, ФИО:

  • SET comment = NULL.
  • SET comment = '[REDACTED]'.
  • ML / NER через anon.partial_text() или external.

Re-identification

PG-AN-070..072: реальная угроза.

Анонимизация имени и email недостаточна, если можно идентифицировать через комбинацию: «профессия + дата рождения + город» — для маленького города уникально.

k-anonymity — каждый объект неразличим от ≥k других по идентифицирующим полям. Сложная техника, для большинства проектов overkill.

Lite-вариант — обобщение полей-идентификаторов (дата рождения → год, город → область).

Что запрещено

АнтипаттернПравилоЧто взамен
Дамп прода без анонимизацииPG-AN-001анонимизация + DPA
Скрипт «по памяти» вне репоPG-AN-041в репо, ревью
Free-text без маскированияPG-AN-062NULL, [REDACTED], NER
Только email замаскированPG-AN-070+ комбинации идентификаторов
Anonymizer-БД оставлена после дампаPG-AN-040удалить сразу
Анонимизация имён без email/phonePG-AN-040весь PII
payment.card_* оставленоPG-AN-040обнулить
Audit_log оставлен с полным историемPG-AN-040retention 7 дней

Куда дальше

  • PG → Анонимизация — нормативные формулировки.
  • Backup — как сделать dump.
  • Расширения — postgresql_anonymizer.
  • Multi-tenancy — анонимизация per-tenant.
  • Auth → PII — что считается PII.
  • Security → secrets — общие принципы.