- Зачем нужна анонимизация баз 1С?
- Что такое pg_anon?
- Постановка задачи для pg_anon
- Реализация
- Установка pg_anon
- Схема работы pg_anon
- Инициализация pg_anon
- Немного теории
- Составление мета-словаря
- Разведка
- Анализ результатов разведки
- Уточнение условий
- Маскирование
- Проверка маскированной базы
- Расширенные возможности
- Заключение
Зачем нужна анонимизация баз 1С?
При разработке и тестировании 1С-систем разработчикам и подрядчикам часто нужна копия базы для разработки. Проще всего - отдать копию продуктива. Так обычно и делают, но это несет определенные риски:
- c точки зрения закона: передача персональных данных сотрудников и клиентов третьим лицам без их согласия нарушает 152-ФЗ, что может грозить компании проверками и штрафами;
- c точки зрения бизнеса: подрядчик, получивший полную базу, видит цены, клиентов, условия контрактов. NDA - это, конечно, хорошо, но информация уже ушла, и что с ней будет дальше, никто не контролирует.
- есть ещё внутренний момент, о котором думают реже: разработчики обычно не проходят те же проверки, что люди, работающие с продуктивными системами. При этом они могут получить в виде копии базы полный доступ к реальным данным.
Выход простой: перед передачей разработчики или подрядчику базу нужно анонимизировать. Реальные данные заменяют правдоподобными, но вымышленными - разработчики получают функционально полную базу и не видят ничего лишнего.
Какие данные необходимо обезличивать?
Персональные данные:
- ФИО
- ИНН
- Серия и номер паспорта
- СНИЛС
- Адреса прописки, проживания и т.д.
Коммерческие данные:
- Номера банковских счетов и карт
- Позиции номенклатуры
- Значения прайсов
- Номера телефонов, email'ы ключевых клиентов, контактных лиц контрагентов
- Данные по скидкам и акциям и т.д.
Корпоративные данные:
- Логины и ФИО пользователей
- IP-адреса и DNS-имена серверов
- MAC-адреса компьютеров
- Логины и пароли доступа к различным сервисам и т.д.
Перед тем как начать, давайте определимся с двумя ключевыми терминами:
- анонимизация/маскирование данных - это процесс преобразование исходных данных в правдоподобные, но не реальные значения, чтобы обезличенную копию БД можно было безопасно использовать для разработки и тестирования без риска раскрытия персональной или конфиденциальной информации;
- сенситивное поле - это столбец базы данных, содержащий персональную или конфиденциальную информацию, которая подлежит обязательному маскированию при обезличивании данных.
В 1С уже есть инструмент для анонимизации базы - обработка "Скрытие конфиденциальной информации", которая также предназначена для маскирования указанных выше данных. Но она имеет ограничения:
- По умолчанию она предлагает к маскированию только поля, связанные с персональной информацией сотрудников, согласно заданному в коде перечню таблиц и полей.
- Необходимо вручную определить другие сенситивные поля.
- Маскирование ссылочных типов может происходить только пообъектно.
- Маскирование необходимо выполнять только на копии базы данных.
Идеальное решение этой проблемы выглядело бы так: обезличивание происходит само, в момент выгрузки дампа продуктивной базы, и незащищенная копия продуктива не создается вообще. Анализировать при этом можно прямо рабочую базу, потому что ее данные только читаются, но не меняются. Ровно так и работает pg_anon, и дальше мы рассказываем подробнее.
Что такое pg_anon?
pg_anon - утилита от "Тантор Лабс" для анонимизации произвольных баз PostgreSQL. К 1С ее никто изначально не готовил - инструмент создавался под любой Postgres и в этом качестве успешно работал, а применение к 1С стало естественным продолжением когда Tantor Postgres закрепился в экосистеме 1С.
Утилита открытая и бесплатная, доступна любому. Проект на GitHub
- https://github.com/TantorLabs/pg_anon, документация на русском
- https://docs.tantorlabs.ru/tdb/ru/18_3/se1c/pg_anon.html
Постановка задачи для pg_anon
Чтобы знакомство с pg_anon было наглядным, разберём его на конкретном сквозном примере.
Изначально я хотел показать работу инструменту на демо-базе БСП, но в итоге отказался от этой идеи: синтетические данные слишком «причесаны» и не отражают реальной картины. На продуктивной базе встречаются куда более интересные случаи - неоднородные данные, исторически накопленные артефакты, нетипичные значения и объекты метаданных - именно на таком материале возможности инструмента раскрываются лучше всего.
Инструмент относительно прост, все описанные далее действия вы без труда сможете повторить на любой типовой или самописной базе 1С.
Задача звучит следующим образом: дана база ERP 2.5 производственной компании размером 646 Гб. Требуется получить ее копию, в которой будут замаскированы все сенситивные данные. Под сенситивными данными понимаем персональные, коммерческие и корпоративные данные. Как правило, хранение таких данных соответствует определенным шаблонам.
Реализация
Для реализации задачи нам понадобится выполнить следующее:
- Установить pg_anon.
- Настроить правила разведки и маскирования.
- Провести тестовую разведку, чтобы понять, все ли мы учли.
- При необходимости написать свои правила разведки и маскирования.
- Выполнить маскирование базы.
- Проверить работоспособность полученной маскированной копии базы.
Тестовый стенд у меня такой:
- Сервер приложений 1С: ОС Astra Linux 1.7.5, 1С Предприятие 8.3.27.1786
- Сервер СУБД: ОС Astra Linux 1.8.1, СУБД Tantor Postgres 18.3.0
Сервер приложений особого значения не играет, а на сервере СУБД у вас обязательно должны быть выполнены условия из раздела "Установка pg_anon" - тогда вы сможете все воспроизвести вместе со мной независимо от версии ОС и СУБД.
Установка pg_anon
Перед установкой убедитесь, что на вашем хосте установлены:
-
Python 3.11+
-
venvдля Python -
Git и pip
-
PostgreSQL или иная СУБД на его основе (например, Tantor Postgres)
Клонируйте репозиторий и перейдите в каталог pg_anon:
git clone https://github.com/TantorLabs/pg_anon.git && cd pg_anon
Создайте виртуальное окружение и активируйте его:
python3 -m venv venv && source venv/bin/activate
Установите зависимости:
pip install .
Проверьте, что установка завершена успешно:
pg_anon --version
Если всё подготовлено корректно - после выполнения последней команды вы увидите основные ключи для работы с инструментом .
Я выполнил установку на сервер, где у меня находится СУБД, но вы можете установить на любой сервер, с которого будет сетевой доступ до вашего сервера баз данных.
Схема работы pg_anon
Прежде чем уже непосредственно запустить pg_anon, давайте рассмотрим схему его работы:
Инициализация pg_anon
Первой командой, которую мы выполним после установки, будет инициализация самой утилиты:
|
Разберем ее параметры:
--mode=init - в данном параметре указывается режим работы инструмента (в данном случае инициализация, далее мы разберем и другие режимы);
--db-user=postgres - имя пользователя СУБД, под которым мы подключаем к инстансу PostgreSQL с базой, которую нужно анонимизировать;
--db-user-password=postgres - пароль пользователя СУБД;
--db-name=erp_v - имя базы 1С на сервере БД, которую требуется анонимизировать;
--db-host=database_server - указывается сервер баз данных;
--db-port=5432 - порт сервера баз данных, на котором располагается инстанс PostgreSQL с анонимизируемой базой.
Эта команда создаст в базе схему anon_funcs с набором пользовательских функций. Именно они и выполняют само маскирование: например, anon_funcs.digest(...) заменяет строку на ее хеш. Мы встретим эти функции уже совсем скоро в правилах мета-словаря и в результатах разведки. Пока достаточно запомнить, что init кладёт в базу «инструменты», которыми pg_anon будет обезличивать данные на следующих этапах.
Немного теории
Прежде чем переходить к самому главному этапу поиска сенситивных полей, необходимо понять, какие поля могут содержать чувствительную информацию в 1С. В типовой базе 1С:ERP распределение типов полей PostgreSQL примерно такое:
| Тип поля | Процент |
| bytea | 45 |
| numeric | 25 |
| mvarchar | 11 |
| boolean | 10 |
| timestamp without time zone | 7 |
| integer | 2 |
| bigint | <0.01 |
| text | <0.01 |
Давайте рассмотрим, какая информация обычно хранится в этих типах полей, чтобы понять, какие из них имеет смысл анонимизировать.
Тип bytea
Этот тип используется в полях ссылочного типа, а также в хранилищах значения, т.е. почти в каждой таблице базы данных. В 1С каждая ссылка представляется через обработчик представления в виде текста, но анонимизировать их смысла нет, т.к. на уровне базы данных содержится просто GUID. В случае анонимизации данного поля будет нарушена ссылочная целостность базы, т.к. различные таблицы ссылаются на конкретный GUID, значение которого маскируется, и как итог, эти таблицы будут ссылаться после маскирования на несуществующий GUID ( <объект не найден>).
Тип numeric
Данный тип встречается во всех полях с типом "Число", т.е. почти в каждой таблице базы данных. Поля типа "Число" требуют точечной анонимизации, поэтому при использовании данного типа нужно указывать конкретно, какие поля базы данных нужно анонимизировать, иначе будут анонимизированы поля, которые сильно затруднят эксплуатацию анонимизированной базы. Например, служебные поля платформы часто имеют именно этот тип:
- _lineno - номер строки в табличной части;
- _sentno, _receivedno - номер отправленного и полученного сообщения в планах обмена;
- _enumorder - поле "Порядок" в перечислениях;
- ОбластьДанныхОсновныеДанные - поле разделителя областей данных;
- _dimhash, _splitter, _edhashdt, _edhashct, _kind, _recordkind - служебные поля регистров;
- _messageno - номер сообщения в таблицах регистрации изменений;
- _usersworkhistory._urlhash - хеш по URL в истории работы пользователей;
- v8users.ussprh - числовое хеш-значение совокупности значений разделителей.
Тип mvarchar
Встречается во всех полях с типом "Строка", т.е. почти в каждой таблице базы данных. Это основной тип данных, подлежащий анонимизации, т.к. именно поля этого типа хранят чувствительную информацию: контактная информация, данные физлиц, названия организаций, контрагентов, номенклатуры и т.д.
Тип timestamp without time zone
Поля данного типа встречаются во всех полях с типом "Дата", как правило, это следующие поля базы данных 1С:
- Поле "Дата" в документах
- Поле "Период" в регистрах накопления, бухгалтерии, сведений
- Поля "ПериодРегистрации", "ПериодДействия*", "БазовыйПериод*" в регистрах расчета
- Любое поле с типом "Дата" в любом объекте метаданных
Поля типа "Дата" требуют точечной анонимизации, поэтому при использовании данного типа нужно указывать конкретно, какие поля базы данных нужно анонимизировать, иначе будут анонимизированы поля, которые сильно затруднят эксплуатацию анонимизированной базы. Например, если анонимизировать поле "Период" в регистре накопления, то движения этого регистра могут разойтись с датой документа, сделавшего движения, и с итогами по данному регистру накопления.
Тип boolean
Встречается во всех полях с булевым типом. Анонимизировать не нужно, поскольку они содержат только два значения, и при их изменении логика работы приложения может быть нарушена.
Другие типы
Для типов integer и bigint характерно то же самое, что и для типа numeric, а для типа text - mvarchar.
Составление мета-словаря
Это самый важный этап, поскольку именно он определяет, какие поля мы будем маскировать. Идея здесь проста - нужен какой-то шаблон, который определяет логику поиска и определения сенситивных полей. Назовем его мета-словарем, то есть набором правил, по которым pg_anon определяет, какие поля считать сенситивными и какой функцией их маскировать. Технически это обычный Python-словарь. Составленный один раз для типовой конфигурации, он легко переносится на другие базы 1С, меняются лишь имена некоторых самописных таблиц и специфичные для компании константы.
Прежде чем разбирать словарь построчно, посмотрим на его структуру сверху. Он состоит из восьми логических блоков:
- Поля без сканирования (
field) - что маскируем принудительно, не заглядывая в данные. - Условия исключения (
skip_rules) - какие таблицы и поля не трогаем вообще. - Условия включения (
include_rules) - в каких таблицах, наоборот, искать в первую очередь. - Регулярные выражения (
data_regex) - по каким шаблонам ловим ИНН, СНИЛС, телефоны, email и т.д. - Константы (
data_const) - какие конкретные значения считать сенситивными. - Произвольные функции (
data_func) - своя логика поиска на любом языке PostgreSQL. - Сенситивные типы данных (
sens_pg_types) - в полях каких типов вообще искать. - Функции анонимизации (
funcs) - чем именно заменять найденное.
Первые шесть блоков отвечают на вопрос «что искать и где», последние два - «где искать и чем заменить». Теперь развернём исходный код и пройдём по каждому блоку:
Поля, которые будут анонимизированы без сканирования
"field": { # Данные поля будут анонимизированы без сканирования
"rules": [],
"constants": []
}
В этом блоке кода можно явно указать имена полей (constants) или регулярные выражения (rules) для поиска полей, которые будут анонимизированы принудительно. Например, если вы хотите анонимизировать все коды или наименования, то можете указать здесь "_code" или "_description", но для 1С бы такой подход не рекомендовал, т.к. мы можем сделать это более гибко и точно с помощью других блоков мета-словаря.
Условия исключения
В данной секции (skip_rules) мы указываем правила, по которым хотим исключить определенные поля и таблицы из анонимизации. Т.е. когда мы точно знаем, что это анонимизировать не нужно.
Пример 1. Явно исключаем типовой регистр сведений "Версии подсистем", т.к. версии подсистем попадают под маску IP-адресов (о которой ниже). Если их анонимизировать, то вместо версий подсистемы мы получим значение, которое при запуске базы приведет к тому, что механизмы БСП не смогут определить версии подсистем, и база просто не запустится после рестора.
{
"schema": "public",
"table": "_inforg92591x1" # Версии подсистем самописные
},
{
"schema": "public",
"table": "_inforg36738" # Версии подсистем
},
В рассматриваемой базе ERP таких регистров сведений было два, один из них самописный.
! Вам для своих баз необходимо определить имена данных таблиц и вставить их в данную секцию, либо не использовать поиск по маске IP-адресов.
Пример 2. Исключаем служебные таблицы платформы 1С, такие как пользователи, история пользователей и другие. В случае их анонимизации база также может не запуститься после рестора из-за нарушения логики.
{
"schema": "public",
"table": "v8users" # Исключаем служебные таблицы 1С
},
{
"schema": "public",
"table": "_usersworkhistory" # Исключаем служебные таблицы 1С
},
{
"schema": "public",
"table_mask": "^_scheduledjobs\\d+$" # Исключаем служебные таблицы 1С
},
{
"schema": "public",
"table_mask": "^_datahistory.*" # Исключаем служебные таблицы 1С
},
{
"schema": "public",
"table_mask": "^_.*settings$" # Исключаем служебные таблицы 1С
}
В поле "table_mask" мы указываем регулярное выражение для поиска таблиц, в поле "table" указываем точное имя таблицы.
Пример 3. Как исключить конкретные поля из анонимизации:
{
"schema": "public",
"fields": ["_dimhash", "_enumorder "] # пример исключения конкретных полей
}
Условия включения
Секция "include_rules" работает по аналогии с секцией "skip_rules", только она не исключает, а определяет таблицы, которые подлежат применению дальнейших правил анонимизации. Другими словами, она позволяет ограничить список таблиц, в которых искать сеститивные данные. Мы ее не заполняем, т.к. в каждой базе 1С будут уникальные имена таблиц, которые содержат сенситивные данные.
Регулярные выражения
Регулярные выражения применяются для поиска сенситивных данных по разным шаблонам. В каждом шаблоне описано, какую чувствительную информацию он ищет, мы постарались предусмотреть все самые распространённые для 1С шаблоны.
"data_regex": {
"rules": [
"[A-Za-z0-9]+([._-][A-Za-z0-9]+)*@[A-Za-z0-9-]+(\.[A-Za-z]{2,})+", # email
"^(7?\d{10})$", # phone 7XXXXXXXXXX
"^\+7 \(\d{3}\) \d{3}-\d{2}-\d{2}$", # phone +7 (XXX) XXX-XX-XX
"^\d{3}-\d{3}-\d{3} \d{2}$", # СНИЛС XXX-XXX-XXX XX
"^\d{2}:\d{2}:\d{1,}:\d{1,}$", # кадастровый номер АА:ВВ:CCCCСCC:КК
"^[А-Я]{1}[0-9]{3}[А-Я]{2}[0-9]{2,3}$", # гос номер авто A111BB777
"^[A-HJ-NPR-Z0-9]{17}$", # VIN номер авто (не включает буквы I, O и Q для предотвращения путаницы)
"^Представление=.*$", # Для некоторых полей представлений
"^\d{1,3}[.]\d{1,3}[.]\d{1,3}[.]\d{1,3}$", # IPV4 адреса
"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$", # Даты в формате 1C - YYYY-MM-DD HH:MM:SS
"^(?:5[1-5][0-9]{2}|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}$", # MasterCard карты 5258704108753590
"\b([4]\d{3}[\s]\d{4}[\s]\d{4}[\s]\d{4}|[4]\d{3}[-]\d{4}[-]\d{4}[-]\d{4}|[4]\d{3}[.]\d{4}[.]\d{4}[.]\d{4}|[4]\d{3}\d{4}\d{4}\d{4})\b", # Visa card карты 4563-7568-5698-4587
"^[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{4}$", # Любая карта
"""(?i)\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()]+|\(([^\s()]+|(\([^\s()]+\)))*\))+(?:\(([^\s()]+|(\([^\s()]+\)))*\)|[^\s`!()\[\]{};:'".,?«»“”‘’]))""", # URLs
"^[a-z0-9.-]+\.[a-z]{2,6}$", # URL в коротком формате - abc.ru
"^(\d{10}|\d{12}|\d{13})$", # ИНН - 10 цифр для физлиц и ИП, 12 цифр для юрлиц. ОГРН - 13 цифр.
]
}
Константы
Этот раздел мета-словаря содержит перечень предопределенных значений. Если такое значение встретится в поле при поиске сенситивных данных, то оно считается сенситивным. В подразделе constants указываются искомые значения целиком, например, константа "company" посчитает поле сенситивным, если в нем будет значение "company first", но не посчитает сенситивным поле со значением "companyfirst". В подразделе partial_constants указывается часть искомого значения, например, частичная константа "compan" посчитает сенситивным как поле со значением "company first", так и со значением "companyfirst".
"data_const": {
"constants": [
"company",
"организация",
"компания",
"морозов",
"иванов",
"кузнецов",
"михаил",
"сергей",
"елена",
],
"partial_constants": [
"алекс",
"рович",
"кузнец",
"виктор",
"ооо",
"моск",
"росси",
"област",
"обществ",
"улиц",
"иван",
"петр",
"представление", # Представление контактной информации
"паспорт", # Представление паспорта
"aleks",
"ivan",
"petr",
"victor",
]
}
Произвольные функции
В данном разделе можно использовать свою произвольную функцию, написанную на любом языке, который поддерживается PostgreSQL. И задать в такой функции логику определения является ли поле сенситивным. В нашем мета-словаре потребности в этом нет, поэтому оставляем его пустым:
"data_func": {}
Пример реализации произвольной функции будет рассмотрен ниже в пункте "Расширенные возможности".
Сенситивные типы данных
В этом разделе указывается перечень типов, которые будут использованы при поиске сенситивных данных. Например, мы указываем "mvarchar", это означает, что поиск сенситивных данных будет только в полях, которые имеют тип mvarchar.
sens_pg_types": [
"mvarchar"
]
Функции анонимизации
В данном разделе указывается соответствие того, какая функция анонимизации будет использоваться для полей с соответствующим типом данных.
"funcs": {
"mvarchar": "anon_funcs.digest(\"%s\"::text, 'salt_word', 'md5')"
}
Для типа mvarchar будет использоваться функция anon_funcs.digest.
Разведка
После составления мета-словаря запускается следующий этап - разведка. Его суть в том, что производится анализ таблиц и полей баз данных согласно составленным правилам из мета-словаря. По факту разведки мы получим список полей и таблиц базы данных, которые содержат сенситивные данные.
Сохраним составленный в прошлом разделе мета-словарь в файл meta_1c_dict.py, скопируем его в корневой каталог pg_anon и запустим этап разведки следующей командой:
pg_anon --mode=create-dict \
--db-user=postgres \
--db-user-password=postgres \
--db-name=erp_v \
--db-host=database_server \
--db-port=5432 \
--meta-dict-file=meta_1c_dict.py \
--output-sens-dict-file=sens_dict_output.py \
--output-no-sens-dict-file=no_sens_dict_output.py \
--processes=4
Рассмотрим параметры команды разведки, которые мы ранее не встречали:
--meta-dict-file=meta_1c_dict.py - указываем путь к файлу мета-словаря, на основании которого будет осуществляться поиск сенситивных полей.
--output-sens-dict-file=sens_dict_output.py - имя файла, в котором будет сохранен список найденных сенситивных полей.
--output-no-sens-dict-file=no_sens_dict_output.py - имя файла, в котором будет сохранен список найденных несенситивных полей.
--processes=4 - количество потоков для распараллеливания процесса.
Также есть несколько параметров, которые влияют на данный этап, но мы их явно не указывали:
--scan-mode - определяет, сканировать ли все данные или только их часть [“full”, “partial”] (по умолчанию “partial”).
--scan-partial-rows - если --scan-mode = partial, определяет количество строк в таблице для сканирования (по умолчанию 10000).
Таким образом, мы сканируем не каждую таблицу целиком, а только 10 тысяч записей. Этого достаточно, чтобы понять, содержит то или иное поле сенситивные данные или нет. По итогам выполнения команды будет выведен лог, который заканчивается так:
2026-07-07 14:02:16,003 - INFO - Progress 99.51%
2026-07-07 14:02:16,599 - INFO - <------------- Finished create_dict mode
2026-07-07 14:02:16,599 - INFO - <============ Finished pg_anon in mode: create-dict, result_code = done, elapsed: 74.12 sec
Этап завершился успешно. Обратите внимание на последнюю строку лога:
elapsed: 74.12 sec
646 Гб. 74 секунды. Ни одной строки продуктива не покинуло сервер.
За эти 74 секунды pg_anon прошёл по таблицам базы ERP и составил список полей, содержащих сенситивные данные. Список найденных полей сохранён в sens_dict_output.py. Взглянем на его начало:
{
"dictionary": [
{
"schema": "public",
"table": "_acc46",
"fields": {
"_description": "anon_funcs.digest(\"_description\"::mvarchar, 'salt_word', 'md5')"
}
},
{
"schema": "public",
"table": "_accumrg50556",
"fields": {
"_fld50570": "anon_funcs.digest(\"_fld50570\"::mvarchar, 'salt_word', 'md5')"
}
}
Мы видим имя схемы, таблицы и имя найденного сенситивного поля, к которому далее будет применено правило анонимизации anon_funcs.digest(\"_description\"::mvarchar, 'salt_word', 'md5'). Давайте узнаем, что это за поле, через структуру таблиц базы данных 1С. Это поле "Наименование" плана счетов "Хозрасчетный". Чтобы понять какое правило мета-словаря привело к тому, что поле было определено как сенситивное нужно еще раз запустить команду разведки, добавив параметр --debug. Это добавит в выводимый лог подробную информацию о том, как шел этап разведки, и самое важное - почему поле было определено как сенситивное.
На каждую операцию pg_anon формируется свой каталог лога. Перейдем в каталог лога /pg_anon/pg_anon_runs/2026/7/7/7900d961-0207-4ab8-8148-cfa14927282a/logs и выполним такой поисковый запрос:
grep -F "_acc46._description is SENSITIVE" logs.log*
Это найдет нам в логах строку, где поле было было определено как сенситивное:
logs.log.10:2026-07-07 14:04:33,937 - DEBUG - ========> Process[main]: Field public._acc46._description is SENSITIVE by partial constant иван
"by partial constant иван" - это означает, что здесь было применено правило частичного вхождения слова "иван". Выполним поиск в самом плане счетов:

С точки зрения логики работы инструмента - все корректно. С точки зрения данного справочника возможно оно и не нужно, но здесь поле "Код счета" по сути заменяет наименование для опытных бухгалтеров, поэтому маскирование данного поля к проблемам привести не должно. Как вариант, можно доработать частичные константы, либо исключить явно эту таблицу из процесса разведки на уровне мета-словаря.
Давайте посмотрим определились ли поля справочника физлиц как сенситивные, но сделаем это немного иначе.
Анализ результатов разведки
В pg_anon предусмотрен специальный режим view-fields для просмотра результатов разведки. Выполним следующую команду:
pg_anon --mode=view-fields \
--db-host=database_server \
--db-user=postgres \
--db-user-password=postgres \
--db-name=erp_v \
--db-port=5432 \
--prepared-sens-dict-file=sens_dict_output.py \
--view-only-sensitive-fields \
--table-name=_reference787 \
--orm-dict-file=struct_1c.json
Рассмотрим новые параметры:
--prepared-sens-dict-file=sens_dict_output.py - указываем имя файла, в котором будет сохранен список найденных сенситивных полей на этапе разведки.
--view-only-sensitive-fields - выводить только сенситивные поля. Если не указать данный параметр, то будут выведены все поля.
--table-name=_reference787 - имя таблицы, по которой мы хотим посмотреть информацию
--orm-dict-file=struct_1c.json - имя файла с соответствием метаданных в терминах 1С и SQL. Указывается для того, если мы хотим получить вывод в формате имен 1С. Данный файл можно получить в базе 1С с помощью обработки, которая выгружает структуру базы данных в JSON - https://github.com/alex7six/DatabaseStructure
В результате выполнения команды получим такой вывод:
Это позволяет очень быстро понять, все ли сенситивные поля были найдены на этапе разведки.
Если выполнить эту же команду без отбора по таблице (--table-name), то получим полный список сенситивных полей по всем таблицам. Удобно сразу оценить, все ли учли при составлении мета-словаря, или передать данный список полей на проверку специалисту по информационной безопасности.
Уточнение условий
Допустим, по итогам анализа этапа разведки мы поняли, что не нашли нужное нам поле с сенситивными данныи. Требуется доработать мета-словарь. Как это сделать просто и быстро? Есть 2 способа, которые покрывают большинство случаев.
Способ "Самое часто упоминаемое слово в таблице".
Его суть состоит в том, чтобы найти самое часто встречающиеся слово в поле таблицы и добавить его в список констант data_const. Для этого по таблице нужно выполнить запрос:
SELECT word, COUNT(*) as frequency
FROM (
SELECT unnest(string_to_array(lower(_Description::text), ' ')) as word
FROM _Reference315
) as words
GROUP BY word
ORDER BY frequency DESC
LIMIT 1;
Где:
_Description- подставить имя вашего поля;_Reference315- подставить имя вашего справочника.
В данном примере я подставил справочник "Контрагенты" и поле "Наименование", и результат запроса вернул:
word | frequency
------+-----------
ооо | 18141
Способ "Регулярное выражение под шаблон"
Подходит для полей с четким шаблоном, например, СНИЛС всегда выглядит как XXX-XXX-XXX XX - под такой шаблон нужно регулярное выражение, которое затем ложится в раздел data_regex. И вот здесь хорошая новость: писать регулярки руками не нужно - шаблон для СНИЛС, ИНН, VIN, номера карты или любого другого формата составляется одним промптом к любому AI-чату. Пишем задачу человеческим языком:
Составь регулярное выражение для поиска полей СНИЛС по шаблону XXX-XXX-XXX XX. Учти, что данный шаблон может встретиться в середине строки, поэтому учти, что количество символов строго фиксировано и начинается с начала строки.
В ответ получаем готовое выражение "^\d{3}-\d{3}-\d{3} \d{2}$" - остается только проверить его SQL-запросом:
SELECT _Fld69920
FROM _Reference787
WHERE CAST(_Fld69920 AS mvarchar) ~ '^\d{3}-\d{3}-\d{3} \d{2}$'
LIMIT 1;
Где:
-
_Fld69920- подставить имя вашего поля; -
_Reference787- подставить имя вашего справочника.
Если результат запроса не пустой, значит наше регулярное выражение работает:
_fld69920
----------------
001-010-283 37
После этого вносим корректировки в мета-словарь и повторяем разведку. И так по кругу: разведка → анализ результатов → уточнение условий → снова разведка. Это и есть та петля, которую вы видели на схеме работы в начале статьи. Каждый проход добавляет в словарь пропущенные шаблоны и убирает ложные срабатывания. Итерируем столько раз, сколько нужно пока список сенситивных полей в sens_dict_output.py нас полностью не устроит.
Маскирование
Для того, чтобы выполнить маскирование, необходимо запустить этап создания дампа:
pg_anon --mode=dump \
--db-host=database_server \
--db-user=postgres \
--db-user-password=postgres \
--db-name=erp_v \
--db-port=5432 \
--prepared-sens-dict-file=sens_dict_output.py \
--output-dir=/pg_data/dumps/anon_dumps/erp_v \
--clear-output-dir \
--config=/home/alexander.simonov/pg_anon/tests/config.yml \
--processes=8
Рассмотрим параметры:
--mode=dump - Этот режим создает анонимизированную резервную копию, используя список найденных сенситивных полей и их правил маскирования
! Безопасность
Обратите внимание: маскирование встроено прямо в дамп. pg_anon не делает сначала копию, а потом обезличивает ее - данные заменяются на лету, в процессе выгрузки. Незащищенной копии продуктива не возникает ни на одном шаге. Именно поэтому весь процесс можно запускать на боевой базе: разведка ее только читает, а дамп забирает данные уже обезличенными.
--prepared-sens-dict-file - список сенситивных полей и их правил маскирования, который мы получили на выходе из этапа разведки;
--output-dir - каталог, в котором будет создана анонимизированная резервная копия;
--clear-output-dir - очищает выходной каталог (--output-dir) от предыдущих дампов или других файлов.
--config - в данном файле задаем путь к утилитам pg_dump и pg_restore, например:
17:
pg_dump: "/opt/tantor/db/17/bin/pg_dump"
pg_restore: "/opt/tantor/db/17/bin/pg_restore"
В результате на данном этапе мы получим дамп базы, в котором сенситивные поля будут замаскированы согласно нашим правилам.
! О дампе
Этот резервный файл может быть восстановлен только с помощью
pg_anonи не может быть восстановлен с помощьюpg_restore
Этап для базы размером 646 Гб в 8 потоков выполнился за 30 минут. Информацию об этом можно найти в логе этапа:
2026-07-17 17:40:24,702 - INFO - <------------- Finished dump data
2026-07-17 17:40:25,452 - INFO - <------------- Finished dump
2026-07-17 17:40:25,453 - INFO - <============ Finished pg_anon in mode: dump, result_code = done, elapsed: 1930.2 sec
Следующим этап это создании копии базы данных из дампа. Создадим пустую базу данных на тестовом сервере:
create database erp_v_anon;
Запустим восстановление базы из анонимизированного дампа:
pg_anon --mode=restore \
--db-host=database_server \
--db-user=postgres \
--db-user-password=postgres \
--db-port=5432 \
--db-name=erp_v_anon \
--input-dir=/pg_data/dumps/anon_dumps/erp_v \
--config=/home/alexander.simonov/pg_anon/tests/config.yml
Рассмотрим параметры:
--mode=restore - восстанавливает анонимизированную резервную копию, созданную с помощью pg_anon в режиме Dump
--input-dir - путь к каталогу, содержащему файлы дампа.
В результате данного этапа анонимизированная копия базы будет восстановлена в базу erp_v_anon. Восстановление базы идет в один поток и заняло почти 4 часа, потому что restore однопоточный (ограничение формата дампа pg_anon):
2026-07-18 00:33:32,406 - INFO - <------------- Finished analyze
2026-07-18 00:33:32,407 - INFO - <------------- Finished restore
2026-07-18 00:33:32,413 - INFO - <============ Finished pg_anon in mode: restore, result_code = done, elapsed: 14068.52 sec
Маскирование продуктивной базы завершено, настало время проверки результата из 1С.
Проверка маскированной базы
Откроем список сотрудников:
Просмотрим данные какого-нибудь сотрудника:
Здесь может показаться, что поля ИНН и СНИЛС не замаскированы, но нет - просто у этих полей задано отображение по маске (например, СНИЛС маска 999-999-999 99), поэтому замаскированное значение отображается цифрами.
Откроем личные данные сотрудника:
Теперь откроем какого-нибудь контрагента:
В данном справочнике по полю ИНН не применяется маска, поэтому отображается реальное значение, которое было получено в результате маскирования.
Карточка номенклатуры:
Базовая визуальная проверка показывает, что все сенситивные данные, которые чаще всего проверяют, анонимизированы.
Давайте проверим работоспособность базы и запустим нагрузочный тест на 40 пользователей длительностью 1 час. Результат теста:
В ходе теста виртуальные пользователи выполняли различные операции с документами - открытие формы списка, документа, проведение - а также действия с обработками. Тест завершился успешно, что подтверждает возможность использовать анонимизированную копию базы для целей разработки и тестирования.
Расширенные возможности
Описанных возможностей pg_anon с головой хватит, чтобы успешно сделать маскирование любой базы 1С. Но стоит упомянуть и о других возможностях инструмента, которые позволят настроить его более гибко.
Белые и черные списки
При создании дампа есть возможность выгружать целиком не все таблицы продуктивной базы данных, а только определенные (белый список). Например, разработчику нужно воспроизвести на копии проблемный запрос на уровне СУБД и посмотреть его план запроса. Зачем для таких случаев выгружать базу целиком? Достаточно ведь выгрузить только таблицы, участвующие в запросе, и если в этих таблицах есть сенситивные данные, то обезличить их. К тому же такой дамп-рестор выполнится гораздо быстрее.
В случае с черным списком наоборот - при создании дампа можно исключить из него определенные таблицы.
Отдельный дамп структуры и данных
Данные режимы могут быть полезны в сочетании с белыми и черными списками. Допустим мы хотим создать копию базы 1С, в которую полностью перенесем только несколько нужных для решения конкретной задачи таблиц (белый список). Но запустится ли такая база в режиме 1С:Предприятие? Нет, платформа 1С увидит, что в структуре базы на уровне СУБД отсутствуют обязательные таблицы и таблицы, описанные в конфигурации базы данных, и в режим 1С:Предприятие мы войти не сможем.
Для решения этой задачи на этапе дампа и рестора мы можем:
sync-struct-dump- выполнить дамп структуры базы данных без анонимизированных данных, который будет содержать описание метаданных всех таблиц базы данных.sync-data-dump- выполняем дамп данных таблиц с учетом белого списка.sync-struct-restore- восстанавливаем только структуру базы данных.sync-data-restore- восстанавливаем только данные таблиц, которые были выгружены с учетом белого списка
Собственные функции маскирования
Есть возможность написать собственную произвольную логику определения, является ли поле сенситивным, и каким образом его нужно анонимизировать. Для этого в мета-словаре есть раздел data_funcs. Пример его заполнения:
"data_func": {
"mvarchar": [
{
"scan_func": "anon_funcs.check_reference_field_name",
"anon_func": "anon_funcs.noise_reference_description(\"%s\", 10)",
"n_count": 1, # How many times "scan_func" have to returns "True" by values in one field. If this count will be reached, then this field will be anonymized by "anon_func"
},
],
}
Мы указываем, что для полей с типом mvarchar на этапе разведки будет вызываться функция check_reference_field_name, которую мы создали в схеме anon_funcs. Пример кода этой функции:
CREATE OR REPLACE FUNCTION anon_funcs.check_reference_field_name(
value TEXT,
schema_name TEXT,
table_name TEXT,
field_name TEXT
)
RETURNS boolean AS $$
BEGIN
-- Проверяем, равно ли field_name "_Description"
IF field_name = '_description' THEN
RETURN true;
ELSE
RETURN false;
END IF;
END;
$$
LANGUAGE plpgsql;
В коде этой функции мы проверяем, что если имя поля равно "_Description", то возвращаем ИСТИНА. Далее требуется написать код произвольной функции noise_reference_description, которая будет анонимизировать данные в таких полях. Вы можете написать свою произвольную логику, либо, например, заимствовать криптографические функции из таких расширений как pgcrypto.
Более подробно о всех возможностях можно прочитать в официальной документации.
Заключение
По итогам работы pg_anon можно выделить следующие преимущества:
- Скорость по сравнению с пообъектной анонимизацией - маскирование базы размером 646 Гб заняло 4,5 часа.
- Продуктив в безопасности по умолчанию. Помните риск из начала статьи - отдать копию продуктива и нарушить 152-ФЗ? pg_anon закрывает его архитектурно: разведка только читает данные, поэтому анализировать можно прямо боевую базу, а маскирование встроено в дамп - обезличенная копия рождается уже обезличенной. Промежуточной незащищенной копии, которую можно потерять или слить, не существует ни на одном этапе.
- Есть вариант работы с GUI из Платформы Tantor - те же сценарии доступны без командной строки, что снижает порог входа для администраторов. Подробнее - https://docs.tantorlabs.ru/tp/6.4/instances/admin_anonymizer.html
- Можно заранее видеть как будут анонимизироваться данные - ежим
view-fieldsпоказывает список сенситивных полей до маскирования, включая имена в терминах 1С. - Возможность создания своих универсальных правил - регулярные выражения, константы и произвольные SQL-функции покрывают любые нетиповые шаблоны хранения данных.
- Легко добавить в ДевОпс пайплайны - работает из командной строки, все параметры задаются флагами, результат воспроизводим между запусками.ю
- Дружит с AI. Самая трудоемкая часть - регулярные выражения, они составляются через любой AI-чат по описанию шаблона на человеческом языке. Порог входа падает: не нужно быть спецом ни по regex, ни по структуре 1С, - достаточно объяснить, что ищем. А само составление словаря при желании можно и автоматизировать.
pg_anon открытый и бесплатный - так что лучший способ оценить его не по статье, а на своей базе. Возьмите тестовую копию, возьмите готовый мета-словарь из статьи и прогоните разведку: даже на этом этапе, за те самые полторы минуты, станет видно, сколько сенситивных полей в вашей базе, и все ли типовые правила их ловят. И поделитесь в комментариях, какие нетиповые шаблоны хранения встретились у вас - самописные регистры, хитрые форматы, неочевидные поля. Мы собираем такие случаи и дополняем универсальный мета-словарь, так что ваш пример может попасть в правила, которыми потом воспользуются другие.
Полезные ссылки:
- Проект на GitHub — https://github.com/TantorLabs/pg_anon
- Документация на русском — https://docs.tantorlabs.ru/tdb/ru/18_3/se1c/pg_anon.html
Александр Симонов, Тантор лабс
Вступайте в нашу телеграмм-группу Инфостарт
