pg_anon: как обезличить базу 1С без промежуточной копии

27.07.26

База данных - Администрирование СУБД

База 1С:ERP размером 646 Гб, полное маскирование за 5 часов - без создания промежуточной незащищенной копии. Разбираем бесплатный pg_anon на сквозном примере с реального продуктива.

 

Зачем нужна анонимизация баз 1С?

При разработке и тестировании 1С-систем разработчикам и подрядчикам часто нужна копия базы для разработки. Проще всего - отдать копию продуктива. Так обычно и делают, но это несет определенные риски:

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

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

Какие данные необходимо обезличивать?

Персональные данные:

  • ФИО
  • ИНН
  • Серия и номер паспорта
  • СНИЛС
  • Адреса прописки, проживания и т.д.

Коммерческие данные:

  • Номера банковских счетов и карт
  • Позиции номенклатуры
  • Значения прайсов
  • Номера телефонов, email'ы ключевых клиентов, контактных лиц контрагентов
  • Данные по скидкам и акциям и т.д.

Корпоративные данные:

  • Логины и ФИО пользователей
  • IP-адреса и DNS-имена серверов
  • MAC-адреса компьютеров
  • Логины и пароли доступа к различным сервисам и т.д.

Перед тем как начать, давайте определимся с двумя ключевыми терминами:

  • анонимизация/маскирование данных - это процесс преобразование исходных данных в правдоподобные, но не реальные значения, чтобы обезличенную копию БД можно было безопасно использовать для разработки и тестирования без риска раскрытия персональной или конфиденциальной информации;
  • сенситивное поле - это столбец базы данных, содержащий персональную или конфиденциальную информацию, которая подлежит обязательному маскированию при обезличивании данных.

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

  1. По умолчанию она предлагает к маскированию только поля, связанные с персональной информацией сотрудников, согласно заданному в коде перечню таблиц и полей.
  2. Необходимо вручную определить другие сенситивные поля.
  3. Маскирование ссылочных типов может происходить только пообъектно.
  4. Маскирование необходимо выполнять только на копии базы данных.

Идеальное решение этой проблемы выглядело бы так: обезличивание происходит само, в момент выгрузки дампа продуктивной базы, и незащищенная копия продуктива не создается вообще. Анализировать при этом можно прямо рабочую базу, потому что ее данные только читаются, но не меняются. Ровно так и работает 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 Гб. Требуется получить ее копию, в которой будут замаскированы все сенситивные данные. Под сенситивными данными понимаем персональные, коммерческие и корпоративные данные. Как правило, хранение таких данных соответствует определенным шаблонам.

 

Реализация

Для реализации задачи нам понадобится выполнить следующее:

  1. Установить pg_anon.
  2. Настроить правила разведки и маскирования.
  3. Провести тестовую разведку, чтобы понять, все ли мы учли.
  4. При необходимости написать свои правила разведки и маскирования.
  5. Выполнить маскирование базы.
  6. Проверить работоспособность полученной маскированной копии базы.

Тестовый стенд у меня такой:

  • Сервер приложений 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

Первой командой, которую мы выполним после установки, будет инициализация самой утилиты:

pg_anon --mode=init \
 --db-user=postgres \
 --db-user-password=postgres \
 --db-name=erp_v \
 --db-host=database_server \
 --db-port=5432

 

Разберем ее параметры:

--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С, меняются лишь имена некоторых самописных таблиц и специфичные для компании константы.

Прежде чем разбирать словарь построчно, посмотрим на его структуру сверху. Он состоит из восьми логических блоков:

  1. Поля без сканирования (field) - что маскируем принудительно, не заглядывая в данные.
  2. Условия исключения (skip_rules) - какие таблицы и поля не трогаем вообще.
  3. Условия включения (include_rules) - в каких таблицах, наоборот, искать в первую очередь.
  4. Регулярные выражения (data_regex) - по каким шаблонам ловим ИНН, СНИЛС, телефоны, email и т.д.
  5. Константы (data_const) - какие конкретные значения считать сенситивными.
  6. Произвольные функции (data_func) - своя логика поиска на любом языке PostgreSQL.
  7. Сенситивные типы данных (sens_pg_types) - в полях каких типов вообще искать.
  8. Функции анонимизации (funcs) - чем именно заменять найденное.

Первые шесть блоков отвечают на вопрос «что искать и где», последние два - «где искать и чем заменить». Теперь развернём исходный код и пройдём по каждому блоку:

Развернуть исходный код
 
 
Этот мета-словарь я составил в процессе анонимизации базы 1С:ERP 2.5 производственной компании одного из наших клиентов. От качества словаря напрямую зависит результат маскирования, поэтому дальше разберем каждый блок подробно.

 

Поля, которые будут анонимизированы без сканирования


"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С:Предприятие мы войти не сможем.

Для решения этой задачи на этапе дампа и рестора мы можем:

  1. sync-struct-dump - выполнить дамп структуры базы данных без анонимизированных данных, который будет содержать описание метаданных всех таблиц базы данных.
  2. sync-data-dump - выполняем дамп данных таблиц с учетом белого списка.
  3. sync-struct-restore - восстанавливаем только структуру базы данных.
  4. 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 можно выделить следующие преимущества:

  1. Скорость по сравнению с пообъектной анонимизацией - маскирование базы размером 646 Гб заняло 4,5 часа.
  2. Продуктив в безопасности по умолчанию. Помните риск из начала статьи - отдать копию продуктива и нарушить 152-ФЗ? pg_anon закрывает его архитектурно: разведка только читает данные, поэтому анализировать можно прямо боевую базу, а маскирование встроено в дамп - обезличенная копия рождается уже обезличенной. Промежуточной незащищенной копии, которую можно потерять или слить, не существует ни на одном этапе.
  3. Есть вариант работы с GUI из Платформы Tantor - те же сценарии доступны без командной строки, что снижает порог входа для администраторов. Подробнее - https://docs.tantorlabs.ru/tp/6.4/instances/admin_anonymizer.html
  4. Можно заранее видеть как будут анонимизироваться данные - ежим view-fields показывает список сенситивных полей до маскирования, включая имена в терминах 1С.
  5. Возможность создания своих универсальных правил - регулярные выражения, константы и произвольные SQL-функции покрывают любые нетиповые шаблоны хранения данных.
  6. Легко добавить в ДевОпс пайплайны - работает из командной строки, все параметры задаются флагами, результат воспроизводим между запусками.ю
  7. Дружит с AI. Самая трудоемкая часть - регулярные выражения, они составляются через любой AI-чат по описанию шаблона на человеческом языке. Порог входа падает: не нужно быть спецом ни по regex, ни по структуре 1С, - достаточно объяснить, что ищем. А само составление словаря при желании можно и автоматизировать.

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

 

Полезные ссылки:

 

Александр Симонов, Тантор лабс

Вступайте в нашу телеграмм-группу Инфостарт

pg_anon анонимизация баз данных маскирование данных персональные данные сенситивные поля PostgreSQL разведка данных регулярные выражения анонимизация ERP безопасность

Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

См. также

Администрирование СУБД Системный администратор 1С:Предприятие 8 Россия Бесплатно (free)

Практическое пошаговое руководство по развертыванию и настройке связки «1С:Предприятие 8.3 (x64)» и MS SQL Server 2019 на подготовленном сервере Windows Server 2019. Статья охватывает весь процесс «с нуля»: от установки системных зависимостей и тонкой оптимизации СУБД под специфику 1С (Collation, мгновенная инициализация файлов, лимиты памяти и сетевые протоколы) до создания клиент-серверной базы данных через штатное окно запуска. Материал ориентирован на системных администраторов и специалистов по внедрению, содержит наглядные скриншоты реальной установки, T-SQL скрипт для подготовки учетных записей и итоговый чек-лист работоспособности системы.

17.07.2026    936    user2209040    1    

5

HighLoad оптимизация Администрирование СУБД Программист Россия Бесплатно (free)

Если вы работаете с 1С на PostgreSQL и жалуетесь на тормоза — скорее всего, дело в join predicate pushdown, которого в стандартном PostgreSQL нет. В MS SQL Server этот механизм работает «из коробки», и при миграции именно запросы к виртуальным таблицам 1С бьют по производительности сильнее всего. В этой статье — реальный кейс от Postgres Professional с разбором плана выполнения, ручным экспериментом и доработкой планировщика СУБД, которая ускорила запросы от 22 до 54 000 раз.

16.06.2026    7114    postgres_professional    13    

11

HighLoad оптимизация Администрирование СУБД Системный администратор Программист 1С:Предприятие 8 Бесплатно (free)

Вышел релиз СУБД Tantor Postgres 18, и мы хотим рассказать о его новых возможностях для работы с приложениями на платформе "1С:Предприятие". В обзоре разберем улучшения планировщика, по традиции коснемся работы временных таблиц и не обойдем вниманием вспомогательные утилиты, которые упрощают поиск и диагностику проблем в высоконагруженных системах. За каждым пунктом - реальные запросы 1С, реальные рабочие базы и сотни часов тестирования!

16.06.2026    2029    Tantor    7    

10

Администрирование СУБД Системный администратор Программист 1С:Предприятие 8 Россия Бесплатно (free)

База 1С за несколько лет эксплуатации разрослась, - стала большой, медленно работает, требует много места и времени для копирования и прочего обслуживания. Нужна ли обязательно свертка или можно обойтись более «мягкими» средствами. Делюсь своим опытном как для новых конфигураций, так и для старых УПП, УТ 10…

01.06.2026    6997    2ncom    30    

11

Администрирование СУБД Системный администратор Программист Бесплатно (free)

Статья рассказывает об опыте перевода больших баз с MSSQL на Postgres и годовой эксплуатации после перехода. Показано, с какими ограничениями утилиты ibcmd можно столкнуться при миграции больших баз и какие подходы помогают безопасно обходить эти проблемы. Приведены наиболее интересные кейсы, выявленные в эксплуатации: особенности настроек Postgres, поведение оптимизатора, тонкости работы логики и статистики, а также редкие, но критичные ситуации с производительностью. Материал будет полезен тем, кто планирует переход на Postgres и хочет заранее понимать реальные риски, подводные камни и проверенные практики их преодоления.

20.04.2026    7950    berserg    12    

27

Администрирование СУБД Программист Бесплатно (free)

Прокачиваем Постгрес с помощью пользовательских функций и процедур.

02.03.2026    3305    SerVer1C    3    

12
Для отправки сообщения требуется регистрация/авторизация