Выгрузка и целостность
Экспорт журнала в CSV и JSON Lines по текущему фильтру, формат файла и проверка цепочки хэшей своими средствами.
Журнал выгружается кнопками «Экспорт CSV» и «Экспорт JSON» в разделе. Выгружается всё, что подходит под текущие фильтры, — без ограничения объёма: сервис проходит журнал страница за страницей до конца, а не отдаёт «первые 10 000 строк». Файл собирается в браузере и скачивается сразу; никаких ссылок «действует 24 часа» и писем на почту.
Сама выгрузка — тоже событие: в журнале появляется auditlog.export с форматом, фильтрами и числом строк.
CSV
Для таблиц и отчётов. Кодировка UTF-8 с BOM (Excel открывает кириллицу без настроек), разделитель — запятая, строки — от старой к новой. Столбцы:
| Столбец | Содержимое |
|---|---|
| ID | номер записи |
| Время (UTC) | ISO 8601 с микросекундами, 2026-09-06T01:22:33.482911+00:00 |
| Время (местное) | то же в вашем часовом поясе — для чтения |
| Организация, Проект | где произошло |
| Вид исполнителя, Исполнитель | участник / коннектор / оператор платформы / система; логин или идентификатор |
| Сессия | идентификатор сессии участника |
| IP, Браузер | адрес и User-Agent подключения |
| Действие, Название | код события и его описание из каталога |
| Операция, Важность | класс действия и важность |
| Тип объекта, Объект | на что направлено действие |
| Описание | строка, которую видит человек |
| Результат, Причина отказа | успех / отказ и причина |
| Детали (JSON) | структурированные параметры |
| Хэш предыдущей записи, Хэш записи | звенья цепочки целостности |
JSON Lines
Для SIEM, скриптов и архивов: одна запись — одна строка JSON, ровно в том виде, как её хранит сервер, от старой к новой. Расширение файла — .jsonl. Поля:
{"id":12,"at":"2026-09-06T01:22:34.101532+00:00","org":"buff-demo","project":null,
"actor_kind":"user","actor":"demo-lead","session":"c2a5…","gid":"9821…","ip":"147.45.197.19",
"user_agent":"Mozilla/5.0 …","action":"auditlog.export","operation":"access","severity":"notice",
"target_kind":null,"target":null,"summary":"Выгружен журнал аудита (json)",
"detail":{"op":"auditlog_list","format":"json","filters":{},"rows":9},"ok":true,"error":null,
"prev_hash":"e5ac…","hash":"81df…"}actor_kind принимает значения user, connector, operator, system; severity — info, notice, warning, critical; operation — create, access, modify, remove, authentication, transfer, execute.
Целостность
Записи каждой организации образуют цепочку: хэш записи считается от хэша предыдущей записи и содержимого текущей (SHA-256). Изменение, вставка или удаление любой записи в середине разрывает цепочку — все последующие хэши перестают сходиться.
В приложении. Кнопка «Проверить целостность» пересчитывает цепочку на сервере и отвечает: сколько записей проверено и цела ли цепочка; если нет — номер первой записи, которая не сходится. Проверка тоже записывается в журнал (auditlog.verify).
Своими средствами. Выгруженный JSON Lines содержит всё, что нужно, чтобы проверить цепочку без нас. Хэш записи считается так:
- Взять поля записи
at, org, project, actor_kind, actor, session, ip, user_agent, action, operation, severity, target_kind, target, summary, detail, ok, error(вdetail— объект как есть). - Сериализовать их в JSON с ключами по алфавиту, без пробелов, без экранирования не-ASCII (
ensure_ascii=Falseв Python). - Хэш = SHA-256 от строки
prev_hash + "\n" + сериализация(для первой записи организацииprev_hashпустой).
Скрипт проверки для файла audit-log.jsonl:
import hashlib, json
FIELDS = ["at", "org", "project", "actor_kind", "actor", "session", "ip", "user_agent",
"action", "operation", "severity", "target_kind", "target", "summary", "detail",
"ok", "error"]
prev = None
for line in open("audit-log.jsonl", encoding="utf-8"):
e = json.loads(line)
body = json.dumps({k: e[k] for k in FIELDS}, sort_keys=True, separators=(",", ":"), ensure_ascii=False)
h = hashlib.sha256(((prev or "") + "\n" + body).encode("utf-8")).hexdigest()
if e["prev_hash"] != prev or e["hash"] != h:
raise SystemExit(f"цепочка нарушена на записи #{e['id']}")
prev = e["hash"]
print("цепочка цела, последний хэш", prev)Скрипт ожидает полную выгрузку организации от первой записи («Всё время», без фильтров): цепочка идёт по всем записям подряд, и выгрузка с фильтром проверяется только начиная с той записи, чей prev_hash вам известен. Храните последний хэш каждой выгрузки: следующая выгрузка должна на него опираться — так вы убедитесь, что между ними ничего не исчезло.
Что стоит знать
- Адрес — как его увидел периметр. IP берётся из соединения с нашим сервером (заголовок пограничного узла), не со слов клиента. Пользователь за корпоративным прокси или VPN будет виден адресом этого прокси.
- Часовой пояс. В файле время в UTC; в интерфейсе — в часовом поясе вашего браузера. Сравнивайте по столбцу «Время (UTC)».
- Объём. Выгрузка идёт страницами по 500 записей до конца; для журнала в десятки тысяч записей это несколько секунд. Кнопка блокируется на время выгрузки, по завершении показывается число строк.