Журнал регистрации 1С для SIEM: на «Нано-УТ» найдены 23 из 23 действий с ролями
Разработка - Инструментарий разработчика
Файлы
ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.
Подписка PRO — скачивайте любые файлы со скидкой до 85% из Базы знаний
Оформите подписку на компанию для решения рабочих задач
Оформить подписку и скачать решение со скидкойВы можете заказать платную доработку или адаптацию этой разработки под вашу конфигурацию на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.
ivanov_iiR продержалась 12 секунд, у sidorov_vvR 5 секунд, три неверных пароля подряд закончились успешным входом. Эти случаи поймали правила корреляции R1 и R2, на всех 43 событиях сработало 16 предупреждений.rights_watch.py и выделение событий пользователей, входов и сеансов; разность ролей; вывод JSON Lines и CEF; инкрементальный режим; правила корреляции на событиях опыта.git archive и tarfile, загрузка в новую базу командами DESIGNER /LoadConfigFromFiles и /UpdateDBCfg; два захода опыта через COM из 32-битного PowerShell (23 действия); третий заход для сопоставления полей записи пользователя; сверка каждого шага с выводом скрипта; тесты из чистой распаковки обоих архивов..lgf и .lgp. Клиент-серверный режим и журнал кластера в проверку не вошли. Запросы для SIEM даны как шаблоны, на самих SIEM они не запускались.Журнал регистрации содержит всё, чтобы SIEM увидела выдачу роли администратора, но в виде, который нужно разобрать: словарь в одном файле, записи в другом, роли GUID-ами, состав «до» восстанавливается по предыдущей записи. Скрипт делает эту работу и отдаёт события в CEF и JSON, а правила корреляции ловят короткую выдачу роли и подбор пароля.
- Запись
_$User$_.Updateхранит состояние пользователя после изменения, из 28 полей я подтвердила опытом положение имени, ролей, признака смены пароля, стандартной аутентификации, запрета менять пароль, полного имени, почты и OpenID. - Журнал не хранит имена ролей и состав до изменения. Имена берутся из выгрузки конфигурации, а выдано и снято считается по состоянию, которое скрипт помнит в файле позиции.
- Неуспешный вход записан с кодом пользователя 0: имя логина лежит в данных события, и без разбора данных все три неуспешных входа при подборе пароля выглядели бы анонимными.
- Файл позиции хранит смещение после последней целой записи, поэтому запись, которую платформа дописывает в момент чтения, попадает в вывод целиком при следующем проходе.
роль администратора, выданная и снятая через 5 или 12 секунд, видна в журнале регистрации с точностью до секунды. SIEM поймает её, когда события лежат в ней с полями «кто», «над кем», «что выдано».
Для кого: администраторы и разработчики 1С, которые передают журнал регистрации в SIEM, и сотрудники SOC, настраивающие правила по событиям прав доступа в 1С.
- Стенд и порядок работы
- Что пишет журнал о пользователях
- Что делает rights_watch
- Опыт: двадцать три действия и двадцать три найденных события
- Повторный запуск выдаёт только новое
- Правила корреляции на событиях опыта
- Формат журнала на платформе 8.3.27
- Опыт на журналах других баз
- Файлы к статье
- Источники
- Итог
Службе безопасности нужно узнавать о выдаче административной роли в 1С в тот же день. Выгрузка прав в Excel раз в месяц такого не даёт. Платформа пишет такие действия в журнал регистрации, но SIEM его не читает: у журнала собственный формат, роли в нём записаны идентификаторами, а прежнего состава пользователя в записи нет. Я написала скрипт rights_watch.py, который читает журнал и выдаёт события в JSON Lines и CEF, и проверила его на «Нано-УТ 2.0» двумя заходами опыта: создала и удалила пользователей через COM, выдавала и снимала роли, вводила неверные пароли.
Стенд и порядок работы
| Условие | Значение |
|---|---|
| Платформа | 1С:Предприятие 8.3.27.2130 x86, файловая база, пакетный запуск DESIGNER, COM-соединение из 32-битного PowerShell |
| Конфигурация | «Нано-УТ 2.0», коммит 8a41e51: 212 XML-файлов, 81 модуль, три роли (Администратор, Оператор, Чтение) |
| Сборка стенда | git archive, распаковка tarfile, CREATEINFOBASE, /LoadConfigFromFiles, /UpdateDBCfg; DESIGNER ответил «Обновление конфигурации успешно завершено» |
| Инструмент | rights_watch.py, Python 3.12.10, стандартная библиотека |
| Компьютер | Windows 11 Pro, Intel Core i5-2400, 7,9 ГБ ОЗУ, SATA SSD, рабочая машина с открытыми приложениями |
| Метод | сценарии на COM создают, меняют и удаляют пользователей; шаги записаны с временем; каждый шаг сверяется с выводом скрипта |
Стенд собирает make_stand.py из архива компаньона: одна команда с путём к репозиторию и коммитом. Базу и журнал каждого захода я оставляю как есть и не очищаю между заходами: во втором заходе рядом с новыми событиями лежат записи первого, и это нужно для проверки инкрементального режима.
Что пишет журнал о пользователях
Журнал старого формата состоит из словаря 1Cv8.lgf и файлов записей *.lgp (файлы по периодам, имя начинается с даты начала периода). В словаре лежат коды пользователей, компьютеров, приложений и событий, в записи стоят только коды и данные. Запись события — это фигурные скобки с полями через запятую: время, статус транзакции, номер транзакции, пользователь, компьютер, приложение, соединение, событие, важность, комментарий, метаданные, данные, представление данных, сервер, порты, сеанс.
Запись пользователя в моём опыте выглядит так (пробелы и переводы строк убраны):
Это запись _$User$_.Update в 21:36:37 (шаг E4, выдана третья роль). Что в ней видно:
- Роли идут массивом
{"A",{3,...}}: число ролей и ссылки на объекты метаданных вида «тип роли, GUID роли». Названий ролей нет:a65ef7fa-...— этоАдминистратор,1b8bedb0-...—Оператор,e2ac1ac5-...—Чтение. GUID совпадают с атрибутомuuidв файлахRoles/*.xmlвыгрузки конфигурации. - В записи полное состояние пользователя после действия, 28 полей. Что было до действия, записать нечем: чтобы получить «выдана роль», нужно сравнить с предыдущей записью того же пользователя.
- Пароля и его хеша в записи нет. Есть дата установки пароля
{"D",20261025203635}(по UTC, у записи журнала время локальное, разница в опыте 1 час) и строкаSHA1. - Удаление хранит только имя:
{"P", { {"S","ivanov_iiR"} } }(внутренний список из одного поля с именем). Роли удалённого пользователя и их количество в записи не лежат. - У неуспешного входа в поле «пользователь» стоит код 0, а логин, который вводили, лежит в данных:
{"P",{518,{"S","ivanov_iiR"},{"S","TOP-DESKTOP\nasch"},{"N",1}}}. Скрипт берёт логин и имя пользователя ОС оттуда. - Вокруг
NewиUpdateплатформа пишет_$Transaction$_.BeginиCommit, вокругDeleteв моих записях транзакционных событий нет.
Положение полей я определила третьим заходом опыта: сценарий probe_user_fields.ps1 менял у пользователя по одному свойству, а diff_user_records.py печатал, какие позиции записи изменились. Результат из журнала probe-diff.txt:
| Что изменила в сценарии | Позиция в данных | Что стало |
|---|---|---|
| имя пользователя | 4 | строка с именем |
АутентификацияСтандартная Ложь, потом Истина |
2 | 1, 0, 1 |
ЗапрещеноИзменятьПароль Истина |
3 | 0, затем 1 |
| запись существующего пользователя с заданным паролем | 6 | 1; при создании пользователя и при записи без пароля 0 |
Пароль пустая строка, потом непустая |
7 | 1, 0, 1: пароль установлен или нет |
ПолноеИмя |
9 | строка |
| состав ролей | 12 | массив ссылок на роли |
АутентификацияOpenID |
13 | 0, затем 1 |
АдресЭлектроннойПочты |
18 | строка |
| установка пароля | 23 | дата установки по UTC |
Свойство ПоказыватьВСпискеВыбора в записи не изменило ни одной позиции: запись пользователя его не содержит, и в события оно не попадает. Остальные позиции в моих записях не менялись ни одним из девяти действий; скрипт их не читает.
Что делает rights_watch
Скрипт открывает журнал на чтение: каталог 1Cv8Log, каталог базы или каталог журнала. Выбор событий задан группами (--events): пользователи (_$User$_.New, .Update, .Delete и ошибки .NewError, .UpdateError, .DeleteError), аутентификация (_$Session$_.Authentication и AuthenticationError), начало и конец сеансов, доступ и отказ в доступе, обновление конфигурации; группа all отдаёт всё подряд. Для пользователей скрипт считает разность ролей и признак смены пароля, а для выдачи роли из списка --admin-role ставит admin_role_added.
Первый запуск на журнале стенда после первого захода (для снимков файлы журнала скопированы в каталог ibR рядом со скриптом):

Рисунок 1. Первый проход: 24 события первого захода опыта. Строки с + показывают выданные роли, с - снятые, у ivanov_iiR видны выдача и снятие роли администратора через 12 секунд.
В журнале на этот момент 24 записи выбранных групп из первого захода: 10 событий пользователей (три создания, четыре изменения, три удаления), 5 входов (четыре успешных и одна ошибка), 8 событий начала и конца сеансов и одно событие «Вход с отключенной проверкой прав» из DESIGNER. Транзакционные записи и обновление конфигурации в вывод не входят: это группы, которые не выбраны.
События записываются в два файла. В JSON Lines одно событие занимает одну строку с полями ts, kind, actor, target, roles_added, roles_removed, roles_after, password_changed, admin_role_added, id. В CEF те же данные в виде act, suser, duser, cs1-cs6; полный разбор полей лежит в README инструмента и в siem-rules.md компаньона. Полный набор из шести событий опыта в обоих видах приведён в event-examples.md; вот выдача роли администратора в CEF:
Опыт: двадцать три действия и двадцать три найденных события
Первый заход, run_rights_experiment.ps1, выполняется через COM из 32-битного PowerShell. Администратор создаётся в базе без пользователей, дальше все действия идут под ним.
| Шаг | Действие | Событие журнала | Что показал скрипт |
|---|---|---|---|
| E1 | создать администратора базы | _$User$_.New |
actor пустой (пользователей ещё нет), роль +Администратор |
| E2 | создать ivanov_iiR с ролью Чтение |
_$User$_.New |
+Чтение |
| E3 | добавить роль Оператор | _$User$_.Update |
+Оператор, итог Оператор, Чтение |
| E4 | добавить роль Администратор | _$User$_.Update |
+Администратор, admin_role_added=true |
| E5 | вход под ivanov_iiR |
_$Session$_.Authentication |
login=ivanov_iiR, actor=ivanov_iiR |
| E6 | неверный пароль | _$Session$_.AuthenticationError |
код пользователя 0 в записи, логин из данных |
| E7 | снять роль Администратор | _$User$_.Update |
-Администратор |
| E8 | сменить пароль | _$User$_.Update |
password_changed=true |
| E9 | создать petrov_ppR сразу с ролью Администратор |
_$User$_.New |
+Администратор, admin_role_added=true |
| E10-E12 | удалить трёх пользователей | _$User$_.Delete |
roles_removed из позиции скрипта |
Шаги записывает сам сценарий: id, действие, пользователь, ожидаемое событие и окно времени. Скрипт check_experiment.py сопоставляет каждый шаг с событием: должны совпасть имя события, цель (пользователь или логин) и время в окне шага плюс две секунды, а для шагов с ролями ещё и выданное со снятым. На шагах E3, E4, E7 и E8 события расположены в соседних секундах, поэтому каждое событие может достаться только одному шагу.
Второй заход, run_second_wave.ps1, проверяет сценарии для правил: администратор soc_adminR создаёт sidorov_vvR с ролью Оператор (W2), выдаёт ему Администратор (W3) и через 4 секунды снимает (W4); затем три неверных пароля подряд (W5.1-W5.3), успешный вход (W6), смена пароля администратором (W7) и удаление обоих (W8, W9). Сверка по всем 23 действиям двух заходов дала 23 найденных:
Состав вывода по группам: 17 событий пользователей (5 создания, 7 изменения, 5 удаления), 11 входов (7 успешных, 4 неуспешных), 14 событий начала и конца сеансов и одно событие доступа; всего 43 события из 76 записей журнала. Остальные 33 записи это транзакции (12 Begin и 12 Commit) и служебные события DESIGNER при загрузке конфигурации.
Повторный запуск выдаёт только новое
В файле позиции, который скрипт пишет после прохода, лежат смещение в байтах после последней целой записи каждого .lgp, формат журнала и последний известный состав ролей каждого пользователя. Повторный запуск сразу после первого вернул ноль событий, а файл JSON Lines остался с теми же 24 строками.

Рисунок 2. Второй проход подряд: 0 событий. Файл позиции хранит смещение 13183 байта и пустой список пользователей (все удалены).
После второго захода опыта я заменила файлы в каталоге ibR журналом стенда целиком, и тот же запуск вернул только новые записи:

Рисунок 3. Третий проход: 19 новых событий второго захода. Видны выдача и снятие роли у sidorov_vvR через 5 секунд, три неуспешных входа и успешный вход.
Три свойства режима проверены тестами. Запись, которую платформа дописывает в момент чтения, не засчитывается: тест обрывает файл на 40 байт раньше конца записи, проход не выдаёт её, после дописывания следующий проход выдаёт её один раз. Усечённый или заменённый файл читается заново, потому что смещение больше его размера. Состав ролей хранится в файле позиции: если оборвать журнал после создания пользователя и прочитать остаток при следующем запуске, выдача роли Оператор у него определяется по состоянию из прошлого запуска. Без такого состояния у существующего пользователя поля roles_added и roles_removed равны null, а в roles_note записана причина.
Правила корреляции на событиях опыта
Правила описаны в siem-rules.md компаньона и реализованы в correlate.py. На 43 событиях опыта они дали 16 предупреждений:
| Правило | Условие | Сработало | Какие случаи |
|---|---|---|---|
| R1 | роль администратора выдана и снята или пользователь удалён не позже чем через 60 секунд | 5 | ivanov_iiR за 12 с, sidorov_vvR за 5 с, три удаления в конце опыта (1, 26 и 37 с) |
| R2 | три неудачных входа одного логина за 5 минут, затем успех | 1 | sidorov_vvR: три неуспешных входа в 21:46:34, :40, :45 и вход в 21:46:50 |
| R3 | учётная запись создана и удалена за час | 5 | все пять созданных пользователей, от 1 до 37 с |
| R4 | пароль сменил не сам пользователь | 2 | ivanov_iiR и sidorov_vvR |
| R5 | пользователь создан сразу с ролью администратора | 3 | admin_nanoR, petrov_ppR, soc_adminR |

Рисунок 4. correlate.py на 43 событиях опыта: 16 предупреждений; check_experiment.py: 23 действия из 23.
Каждое правило сопровождено ключами порогов. Окно R1 в 6 секунд оставляет два предупреждения (petrov_ppR и sidorov_vvR), порог R2 в четыре неуспешных входа убирает его совсем: тесты test_r1_window_shorter и test_r2_needs_three. Для правила вне рабочего времени (R6) задаётся интервал --work-hours; на опыте, который шёл вечером, оно даёт предупреждение на каждое из 17 событий пользователей.
Три срабатывания R1 с удалением и пять срабатываний R3 принадлежат уборке стенда в конце захода: пользователи создавались ради опыта и сразу удалялись. В рабочей базе такой след означает разовую учётную запись и достоин проверки.
Формат журнала на платформе 8.3.27
Платформа 8.3.27.2130 пишет журнал файловой базы только в 1Cv8.lgf и *.lgp. Я положила готовый 1Cv8.lgd в каталог 1Cv8Log свежей базы: платформа создала рядом 1Cv8.lgf и .lgp, события пошли в них, размер .lgd остался прежним. Среди команд «Настройки журнала регистрации» переключателя формата нет. По статье на Хабре «Записки оптимизатора 1С (ч.13)» (ссылка в разделе «Источники»), начиная с 8.3.22 платформа не конвертирует журнал в SQLite и не поддерживает этот формат. Файлы .lgd встречаются в базах, которые работали на платформах 8.3.5-8.3.21, и в архивах их журналов. Скрипт читает такие файлы по схеме таблиц, которую выдала платформа, и проверен на файле, собранном из записей настоящего журнала: те же события, роли, цели и время, что на текстовом журнале (evidence/check-experiment.txt).
Опыт на журналах других баз
Чтобы проверить скрипт на данных, которых я не создавала в опыте, я прогнала его (только чтение, --events all) на журналах трёх других файловых баз этого компьютера:
| База | Размер журнала | Время | Записей | Находки |
|---|---|---|---|---|
| «Нано-УТ» (другая копия) | 52 КБ | 0,2 с | 264 | 54 входа |
| демобаза УТ | 25 МБ | 28,2 с | 246 014 | 292 входа, 95 неуспешных входов |
| большая рабочая база автора | 184 МБ | 196,1 с | 1 656 117 | 451 вход, 127 неуспешных входов, 1 создание и 4 изменения пользователей, 1 отказ в доступе |
Код возврата во всех трёх прогонах 0. Скорость около 0,9 МБ в секунду на этом компьютере при выводе каждого события.
Файлы к статье
К статье приложены два архива.
Инструмент rights-soc-26-3-tool.zip содержит rights_watch.py, README с описанием полей и пределов проверки, 21 тест и данные для них: журнал первого захода (словарь и записи), справочник ролей. Запуск из корня распакованного архива:
Компаньон rights-soc-26-3-companion.zip содержит правила корреляции на событиях опыта (siem-rules.md), correlate.py и check_experiment.py, события опыта в JSON и CEF, шесть событий с разбором, чек-лист внедрения, сценарии COM для обоих заходов и сопоставления полей, make_stand.py для сборки стенда, журналы запусков и 9 тестов.

Рисунок 5. Тесты из распакованных архивов: 21 тест инструмента и 9 тестов компаньона, платформа не нужна.
Источники
- Записки оптимизатора 1С (ч.13). Что не так в журнале регистрации 1С в формате SQLite? - про исключённую с 8.3.22 конвертацию журнала в SQLite.
Итог
Журнал регистрации 1С 8.3.27 даёт SIEM события изменения пользователей с точностью до секунды и с составом ролей после действия. Скрипт rights_watch.py нашёл все 23 действия двух заходов опыта на «Нано-УТ 2.0» и выдал выдачу и снятие ролей в JSON Lines и CEF. Правила корреляции поймали роль администратора, снятую через 12 и 5 секунд, и подбор пароля с успешным входом.
Практический смысл: администраторам и SOC достаточно прочитать журнал и сохранить состав ролей по пользователям, чтобы получить события «выдана роль» и «снята роль» с именами. Для имён ролей нужна выгрузка конфигурации, для надёжного «выдано, снято» нужен файл позиции с резервной копией.
Выводы относятся к платформе 8.3.27.2130, файловой базе и текстовому журналу .lgf и .lgp. Клиент-серверные базы и журнал кластера, ограничения на уровне записей и профили групп доступа БСП (в событиях _$User$_.* их нет) в проверку не вошли; запросы для Splunk и Elastic в компаньоне остаются шаблонами.
Вступайте в нашу телеграмм-группу Инфостарт