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

Что именно писать и чего писать нельзя, если в системе есть персональные данные, разобрано в статье «Защита персональных данных в веб-приложении». Здесь о другом: как построить сам журнал, чтобы он выдержал расследование. Описание услуги — на странице «Логирование и аудит действий пользователей».

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

Три журнала, которые путают

В приложении обычно уже есть «логи», и на этом основании журнал действий считают сделанным. На деле это три разных вещи с разными читателями, сроками и правами доступа.

ЖурналДля когоЧто внутриСрок и доступ
ТехническийразработчикОшибки, предупреждения, время ответов, трассировка запросаКороткий срок; доступ у команды разработки; данные пользователей маскируются
История объектапользователь и менеджерЧто менялось в заказе, договоре, карточке: «статус изменён», «сумма изменена», автор и времяЖивёт столько же, сколько объект; показывается в интерфейсе тем, кому разрешено
Журнал аудитавладелец системы, безопасность, внешний проверяющийВходы, смена прав, чтение защищённых данных, выгрузки, удаления, действия поддержки, отказы в доступеДольше технического; доступ у узкого круга; правка записей закрыта

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

С чего начать: шесть вопросов, на которые журнал должен отвечать

Журнал без вопросов превращается в свалку событий, где нужное не находится. Начните со списка, который можно показать владельцу системы и подписать:

  • Кто менял условия договора или цену? Нужны автор, время, объект и значения до и после.
  • Кто выгрузил список клиентов? Нужны автор, фильтр, число записей и способ получения файла.
  • Откуда заходил пользователь, чей доступ использовали? Нужны адрес, устройство, способ входа и неудачные попытки до успеха.
  • Почему у сотрудника есть право, которого быть не должно? Нужны смена ролей: кто выдал, когда, по какой заявке.
  • Что сотрудник поддержки делал от имени клиента? Нужны сам факт входа, причина, перечень открытых разделов.
  • Что показать клиенту или проверяющему за квартал? Нужен отчёт по организации или пользователю за период.

У каждого вопроса есть свой набор событий. Если вопрос нельзя сформулировать, событие в журнал не идёт: лишние записи увеличивают объём и затрудняют поиск нужных.

Из чего состоит запись

Запись должна быть самодостаточной: через год, когда пользователь уволен, а справочник изменился, по ней должно быть понятно, что произошло. Достаточно девяти полей.

ПолеПримерЛовушка
Времямомент события в единой временной зонеРазные часы на серверах: события выстраиваются в неверном порядке
Субъектидентификатор пользователя и организацииЗапись по имени или почте: после смены имени связь теряется
От чьего именисотрудник поддержки действует как клиентЗаписан только клиент, и поддержка остаётся невидимой
Действиекод из справочника: заказ.цена.изменениеСвободный текст: поиск и отчёты невозможны
Объекттип и идентификатор: заказ, номерНазвание вместо идентификатора, которое потом меняется
Результатуспех, отказ в доступе, ошибкаПишут только успехи, и попытки обхода не видны
Источникадрес, приложение, версия клиентаАдрес прокси вместо адреса пользователя
Изменениекакие поля и значения до и после для обычных данныхЗначения чувствительных полей попадают в журнал, и он становится утечкой
Сквозной номеридентификатор запросаНет связи с технической трассой, подробности приходится искать вручную

Справочник действий важнее, чем кажется. Он превращает журнал из текста в данные: «все выгрузки за месяц» или «все смены прав у этой роли» становятся запросом, а не чтением длинных списков. Справочник ведут как код: новое событие появляется вместе с функцией, которая его порождает, и проходит ревью.

Где в коде писать и что делать, если запись не удалась

Самая частая ошибка — раскидать вызовы журнала по обработчикам запросов. Часть операций забывают, часть дублируют, а при переносе функции запись теряется. Надёжнее выбрать одно из мест.

МестоЧто ловитЧто пропускаетКогда выбирать
Слой бизнес-операцийСмысловые события: «согласовано», «цена изменена», «роль выдана»Прямые правки в базе в обход приложенияОсновной вариант для нового приложения
Промежуточный слой запросовЧтение защищённых страниц, отказы в доступе, входыСмысл действия: видно «PUT на адрес», но не «что изменили»Дополнение к слою операций для событий доступа
Триггеры базы данныхЛюбое изменение таблицы, в том числе из скриптаКто из пользователей приложения это сделал, если не передавать его в сеансСтарые системы без возможности менять код; защита от правок в обход

В одной транзакции с операцией или отдельно

Если запись об изменении цены сохраняется в одной транзакции с самим изменением, они появятся вместе или не появятся вообще. Цена — задержка на запись и риск: сбой журнала останавливает операцию. Для событий с последствиями (деньги, права, удаление, выгрузка) это нужная цена: лучше отказать, чем сделать невидимо. Для менее важных событий, например просмотра справочника, допустима очередь: запись уходит в журнал асинхронно, а при остановке очереди события копятся в промежуточном хранилище, и потеря допускается только в заранее оговорённом объёме.

Решение «важное событие — в транзакции, остальное — через очередь» записывается в документе и проверяется тестом: отключаем хранилище журнала и смотрим, что делает приложение. Ответ «ничего не заметило» означает, что события теряются молча.

Как защитить журнал от правки

Журнал, который можно поправить, ничего не доказывает. Защита строится слоями, и каждый слой закрывает свою угрозу.

  • Отдельная учётная запись для записи. У приложения право только добавлять строки в таблицу журнала, без обновления и удаления. Это закрывает правку через ошибку в приложении.
  • Отдельное хранилище. Журнал лежит вне основной базы, с отдельным доступом. Читать его может узкий круг, и это не те, чьи действия записаны.
  • Копия вовне по расписанию. Записи регулярно выгружаются в хранилище, где их нельзя перезаписать. Если оригинал изменили, расхождение видно.
  • Цепочка контрольных значений. Каждая запись содержит контрольное значение предыдущей, и подмена записи в середине ломает цепочку. Это защищает от тихой правки, но не от удаления последних записей, поэтому дополняет копию вовне, а не заменяет её.
  • Единое время. Часы серверов синхронизируются с одним источником, иначе порядок событий оспорим.

Честная граница: от администратора базы данных с полным доступом журнал, лежащий в той же базе, не защищает. Поэтому в чувствительных системах журнал выносят в хранилище, администратор которого не совпадает с администратором основной базы. Защита журнала не заменяет разграничение прав в самом приложении, о котором см. статью о технических мерах защиты.

Как читать журнал, чтобы он не лежал мёртвым грузом

Запись, которую никто не открывает, имеет ценность только после происшествия, когда читать приходится в спешке. Заранее делаются три способа чтения.

Способ чтенияКто пользуетсяКак устроеноПример
История объектаменеджер, руководительВкладка в карточке заказа или договора со списком изменений«Кто и когда изменил срок поставки»
Расследованиеответственный за безопасностьПоиск по пользователю, действию, объекту и периоду, выгрузка результата«Что делал этот логин в день инцидента»
Оповещениеответственный за безопасностьПравило на порог: массовая выгрузка, много отказов подряд, выдача административной ролиПисьмо или сообщение в рабочий чат
Просмотр клиентомадминистратор организации-клиентаРаздел «Журнал активности» с фильтром по своим сотрудникам«Кто из наших сотрудников скачал документы»

Объём и срок хранения

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

Приёмка и типичные ошибки

Журнал проверяют так же, как права: не по наличию, а по поведению. Восемь проверок, которые стоит пройти до запуска и повторять после крупных изменений.

  1. Выполнить каждое действие из справочника и найти его запись по номеру запроса.
  2. Выполнить действие с отказом (чужой объект, нет роли) и убедиться, что отказ записан.
  3. Попробовать изменить и удалить запись под учётной записью приложения: операция должна быть отклонена.
  4. Отключить хранилище журнала: важные операции останавливаются, остальные копят события в очереди.
  5. Проверить, что в записях нет паролей, токенов, содержимого форм и значений чувствительных полей.
  6. Войти от имени клиента из-под поддержки: в записи видны оба — клиент и сотрудник.
  7. Ответить на каждый из шести вопросов, заданных в начале, только по журналу, не открывая код.
  8. Восстановить журнал из копии и сравнить с оригиналом.

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

Что делаем мы и с чего начать

Начинаем с обследования: 200 000 ₽ и 2–3 недели за одно-два приложения, 350 000 ₽ и 3–4 недели, если систем несколько. Записываем вопросы к журналу, список событий и справочник действий, проверяем, что уже пишется и где, выбираем место записи и хранилище. Обследование вычитается из первого этапа, если продолжаете с нами, а список вопросов и справочником пользуются и без нас.

Дальше лёгкий пилот (150 000–400 000 ₽) добавляет журнал к одному приложению: запись в сервисном слое, отдельное хранение, поиск и просмотр по объекту. Сопровождение стоит 20 000 / 60 000 / 120 000 ₽ в месяц. Мы не поставляем SIEM, не дежурим круглосуточно, не проводим аттестацию, лицензии ФСТЭК у нас нет; сроки хранения и состав обязательных записей определяет юрист заказчика. Код и журнал остаются в вашем репозитории и на ваших серверах. Цены и сроки — на странице «Тарифы», описание услуги — на странице «Логирование и аудит действий пользователей».

Частые вопросы

Как вести журнал действий пользователей в простом приложении?

Одна таблица и один сервис записи: время, пользователь, действие из справочника, объект, результат, адрес и номер запроса. Запись вставляется в той же транзакции, что и операция, а у приложения нет права её менять. Этого достаточно для небольшой системы; остальное добавляется по мере роста требований.

Чем журнал аудита отличается от журнала ошибок?

Журнал ошибок отвечает на вопрос, что сломалось, и нужен разработчику. Журнал аудита отвечает на вопрос, кто что сделал, и нужен владельцу системы и проверяющему. У них разные сроки хранения, доступ и требования к сохранности.

Можно ли хранить журнал в той же базе, что и данные?

Можно на старте, если у приложения есть право только вставки и доступ к таблице у узкого круга. В чувствительных системах журнал выносят в отдельное хранилище с другим администратором, иначе тот, кто управляет базой, может изменить и записи о своих действиях.

Нужно ли писать в журнал просмотры?

Только просмотры защищённых данных: карточка человека с персональными данными, документы, финансовые показатели. Запись каждого открытия справочника увеличивает объём и скрывает нужное. Список просматриваемых объектов определяется вопросами к журналу.

Что делать, если запись в журнал не удалась?

Для операций с последствиями (деньги, права, удаление, выгрузка) операция отклоняется: невидимое действие хуже недоступной функции. Для остальных событий допустима очередь с промежуточным хранилищем и заранее оговорённым объёмом возможной потери.

Помогает ли цепочка контрольных значений?

Она делает тихую подмену записи в середине журнала заметной. Но она не защищает от удаления последних записей и не заменяет отдельное хранилище и копию вовне. Это дополнительный слой, а не основная защита.

Как показать журнал клиенту в B2B-сервисе?

Отдельным разделом «Журнал активности» для администратора организации: фильтр по сотрудникам, действиям и периоду, выгрузка за период. Важно, чтобы клиент видел только записи своей организации, и это проверяется отдельным тестом изоляции.

Сколько стоит добавить журнал аудита?

Обследование стоит 200 000 ₽ (350 000 ₽ для нескольких систем) и вычитается из первого этапа, если продолжаете с нами. Лёгкий пилот на одном приложении — 150 000–400 000 ₽. Точная цена зависит от числа событий, места записи и требований к хранению.