Опирается на правила:
PG-AN-001…PG-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-062 | NULL, [REDACTED], NER |
| Только email замаскирован | PG-AN-070 | + комбинации идентификаторов |
| Anonymizer-БД оставлена после дампа | PG-AN-040 | удалить сразу |
| Анонимизация имён без email/phone | PG-AN-040 | весь PII |
payment.card_* оставлено | PG-AN-040 | обнулить |
| Audit_log оставлен с полным историем | PG-AN-040 | retention 7 дней |
Куда дальше
- PG → Анонимизация — нормативные формулировки.
- Backup — как сделать dump.
- Расширения —
postgresql_anonymizer. - Multi-tenancy — анонимизация per-tenant.
- Auth → PII — что считается PII.
- Security → secrets — общие принципы.