# Как определить первый разрыв в журнале аудита с хеш-цепочкой

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

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

## Разорванная связь отмечает конец доказательства, а не начало обвинений

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

Это кажется очевидным, пока в отчете об инциденте не появляется фраза: «запись 842 была изменена». Возможно, именно запись 842 впервые показала проблему, но изменить могли запись 841. Между ними могла исчезнуть запись. Ошибка хранения могла повредить один байт в любой из записей. Копирование журнала могло оборваться, оставив поврежденный хвост. Цепочка говорит только о том, что связь нельзя проверить. Она не определяет механизм.

Разделяйте следующие понятия:

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

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

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

## Сначала сохраните байты, а потом просите парсер объяснить их

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

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

```sh
mkdir -p case-2026-07-22
cp -p /path/to/audit-log.bin case-2026-07-22/audit-log.bin
stat -f '%z bytes  %N' case-2026-07-22/audit-log.bin
shasum -a 256 case-2026-07-22/audit-log.bin
```

Последняя команда выведет результат примерно такого вида:

```text
9d5e...c41a  case-2026-07-22/audit-log.bin
```

Запишите полный хеш, а не сокращенное представление. Также укажите исходный путь, время получения с часовым поясом, имя хоста или идентификатор устройства по правилам работы с доказательствами, оператора и то, продолжало ли приложение записывать файл во время получения. Если журнал был активным, позже получите вторую копию. Копии, в которых разрыв обнаруживается в разных местах, могут указывать на незавершенную запись, а не на устойчивое историческое повреждение.

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

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

Для Sallyport начните с `sp audit verify`, запустив проверку сохраненной копии audit-log или поддерживаемого источника аудита продукта. Цепочку аудита можно проверять офлайн поверх шифротекста, поэтому результат не требует доступа к хранилищу. Сохраните в материалах дела точную команду, код завершения и полный вывод. Не составляйте «аккуратное» резюме по частичному снимку терминала.

## Смещение в байтах должно указывать на полученный файл

Смещение в файле, это число байтов от начала полученного файла доказательств до определенного места. Это стабильная координата для другого специалиста. Номер записи такой координатой часто не является.

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

По возможности указывайте два смещения:

1. Смещение начала последней корректной записи.
2. Смещение начала первой записи с несовпадением.

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

В построчном экспорте `grep -b` может найти известный идентификатор по позиции в байтах, но используйте это лишь как вспомогательный прием и только после проверки, что идентификатор записан буквально и встречается однозначно. Для бинарных или зашифрованных записей используйте hex-просмотрщик, который не изменяет файл. Простая команда просмотра позволяет зафиксировать байты вокруг известной позиции:

```sh
xxd -g 1 -s 104832 -l 256 case-2026-07-22/audit-log.bin
```

Число после `-s`, это смещение в байтах. Вывод начинается с шестнадцатеричных смещений, затем идут значения байтов и, когда возможно, их ASCII-представление. Сохраните этот фрагмент как артефакт анализа, но не подменяйте им полный файл.

Ясно укажите, что означает смещение. Фраза «смещение 104832» недостаточна. Напишите: «Первая запись с несовпадением начинается со смещения 104832 в байтах в файле с SHA-256 9d5e...c41a, отсчет ведется от нулевого байта полученного файла». Если в журнале есть заголовок контейнера, скажите, включен ли он в смещение. Он должен быть включен, поскольку другой специалист будет открывать полученный файл, а не внутренний поток записей вашего парсера.

Частая ошибка в отчетах, указать смещение после распаковки. Оно может помочь разработчику воспроизвести проблему парсера, но не указывает место в файле доказательств. Указывайте оба значения только с ясными пометками: одно относится к необработанным доказательствам, второе, к производной копии для анализа.

## Проверяйте записи по порядку и прекращайте доверие на границе разрыва

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

Не просматривайте файл до конца в поисках более позднего несовпадения, которое выглядит серьезнее. Объем доказанного определяется самой ранней ошибкой. Более поздние ошибки могут быть ее следствием, независимыми дефектами или результатом того, что парсер потерял синхронизацию.

Полезный формат вывода выглядит так, даже если ваш проверяющий использует другие имена полей:

```text
verification_status: failed
last_valid_record: 841
last_valid_offset: 104576
first_mismatch_record: 842
first_mismatch_offset: 104832
failure_kind: predecessor_hash_mismatch
expected_predecessor: 6f4a...
observed_predecessor: c928...
affected_session_ids: sess-17, sess-21, sess-24
```

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

Точно классифицируйте ошибку. Эти случаи имеют разные последствия:

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

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

NIST Special Publication 800-92 рассматривает управление журналами не только как хранение: организациям нужно настраивать источники, анализировать журналы, реагировать на события, хранить данные и проверять сам процесс управления журналами. Это правильная операционная рамка для сбоя цепочки. Проверяющий показывает, где заканчивается подлинность. Чтобы понять причину, нужно изучить сбор данных, хранение, конечные точки и записи о реагировании.

## Сессия может пересекать границу, даже если в ней не появляется запись на самой границе

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

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

| Класс сессии | Картина доказательств | Как отражать в отчете |
| --- | --- | --- |
| Полностью подтверждена | Начало, действия и завершение находятся до разрыва | История, подтвержденная цепочкой, остается целостной |
| Пересекает границу | Данные о сессии есть до и после разрыва | Ранние действия подтверждены, поздние не подтверждены |
| Впервые видна на границе | Первое появление приходится на запись с несовпадением | Вся наблюдаемая история сессии считается неподтвержденной |
| Только в суффиксе | Все наблюдаемые записи находятся после разрыва | Это зацепка для расследования, а не подтвержденная история |
| Возможно пропущена | Внешние данные ссылаются на сессию, отсутствующую в цепочке | Исследуйте это как пробел, а не как обычную сессию суффикса |

Не решайте по одним временным меткам, пересекала ли сессия границу. Часы расходятся, записи могут буферизоваться, а модуль записи может сбрасывать их пакетами. Используйте идентификаторы сессий, идентификаторы процессов, если они доступны, идентификаторы запусков агентов, идентификаторы корреляции действий и явные записи о начале или завершении. Если система не предоставляет все эти поля, укажите ограничение, а не делайте вид, что временного интервала достаточно.

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

```text
Boundary: valid record 841 at offset 104576
          mismatch record 842 at offset 104832

Session sess-17
  first observed: record 809, verified
  last verified action: record 838
  later references: records 842-850, unverified
  classification: crossing

Session sess-21
  first observed: record 842, unverified
  supporting evidence: endpoint process journal reference
  classification: first seen at boundary
```

В листе нужно указывать источник доказательств для каждого вывода. Подтверждением может быть журнал сессии, запись процесса на конечной точке, событие приложения, квитанция удаленного API или журнал SSH-сервера. Недостаточно написать, что сессия «вероятно была активна». Следователю нужно понимать, основан ли вывод на цепочке, другом журнале или заявлении оператора.

Sallyport хранит запуски агентов в журнале Sessions, а отдельные вызовы, в журнале Activity. Оба представления строятся из одного зашифрованного журнала аудита с хеш-цепочкой. Поэтому граница цепочки важна для обоих представлений, но удобное отображение журнала не заменяет результат проверки. Используйте журналы, чтобы найти сессии и вызовы для изучения, а затем указывайте статус цепочки для каждого утверждения.

## Для последней полной записи нужно принять отдельное решение

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

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

Сообщите один из следующих результатов, а не расплывчатую комбинацию:

- «Последняя полная запись проходит проверку; файл заканчивается 73 байтами, которые не образуют полную запись».
- «Последняя полная запись начинается со смещения 104832 и не проходит проверку ссылки на предыдущую запись».
- «Последняя запись объявляет 512 байт, но остается только 301 байт; вычислить хеш содержимого невозможно».

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

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

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

## Сравните независимые копии, прежде чем называть это изменением

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

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

Используйте такую схему решений:

1. Если две независимо полученные копии ломаются на одной записи и одном смещении, а предыдущие байты совпадают, проблема, вероятно, существовала до получения данных. Это все равно не доказывает намерение.
2. Если одна копия проверяется дальше другой, сравните файлы побайтно вокруг первого расхождения. Более короткая или поврежденная копия может быть неполной.
3. Если обе копии внутренне проверяются, но отличаются целиком, выясните, являются ли они отдельными допустимыми сегментами, экспортами с разной областью или признаком замены.
4. Если предполагаемо идентичная копия меняет хеш между чтениями, остановите анализ цепочки и изучите исходный носитель, активный процесс записи, разрешения и процедуру сбора.

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

Внешние журналы действий помогают сузить область. Если агент вызвал HTTP API, идентификаторы запросов, записи аудита на стороне поставщика и изменения ресурсов могут показать, произошло ли действие. При использовании SSH могут помочь записи аутентификации и команд на удаленном сервере. Эти данные не возвращают криптографическое доверие поврежденному суффиксу, но могут независимо подтвердить факты и показать сессии, требующие блокировки.

## Напишите отчет так, чтобы другой специалист мог воспроизвести проверку

Хороший отчет содержит узкое утверждение и достаточно деталей для его проверки. Он не прячет неопределенность за широкими формулировками вроде «целостность аудита нарушена».

Используйте следующий каркас:

```text
Artifact
  Evidence file: audit-log.bin
  SHA-256: <full digest>
  Size: <bytes>
  Source and acquisition reference: <case record>

Verification
  Tool and version: <verifier>
  Command: <exact command>
  Result: failed
  Last valid record: <stable ID and ordinal>
  Last valid record offset: <raw byte offset>
  First mismatch record: <stable ID and ordinal>
  First mismatch offset: <raw byte offset>
  Failure classification: <specific classification>

Scope
  Verified sessions: <identifiers>
  Crossing sessions: <identifiers>
  First seen at boundary: <identifiers>
  Suffix-only sessions: <identifiers>
  Related external evidence: <sources and references>

Limits
  The hash chain verifies the prefix through <record>.
  The chain does not establish the cause of the mismatch.
  Records after <offset> require independent corroboration.

Actions taken
  Evidence preserved: <references>
  Access or session revocations: <references>
  Copies compared: <references>
  Follow-up owner and deadline: <names or case roles>
```

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

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