Наблюдаемость: SIEM-журнал с хеш-цепочкой и отчётность об отрисовке
Модуль Observability предоставляет реализацию, основанную на состоянии среды выполнения: устойчивый к подделке журнал событий SIEM (security information and event management) с хеш-цепочкой, агрегацию отчётов об отрисовке и пилотных запусках, журнал аудита HSM (hardware security module), а также полноценные холостые реализации метрик и трассировки, поэтому инструментирование всегда доступно для вызова.
Одна каноническая страница на каждую тему. Контракты наблюдаемости —
ContextAwareExceptionInterface,SpectrumInterface,JobNotificationInterfaceи перечислениеDegradationPolicy— описаны на странице Contracts / Observability. Эта здесь описана конкретная реализация на основе состояния среды выполнения. Эти страницы дополняют друг друга, а не дублируют: используйте страницу контрактов для интерфейса поставщика услуг (service provider interface, SPI), а эту страницу — для SIEM-журнала, отчётности и интерфейсов аудита.
Установка
Заголовок раздела «Установка»composer require nextpdf/core:^3Концептуальный обзор
Заголовок раздела «Концептуальный обзор»Этот модуль преобразует состояние среды выполнения движка в долговременный проверяемый вывод.
HashChainSiemEventLog — это интерфейс уровня безопасности. Он реализует контракт SiemEventEmitter и записывает журнал в формате JSON Lines (JavaScript Object Notation), где хеш каждой записи равен
SHA-256(prev_hash_bytes || canonical_event_bytes). Эта линейная хеш-цепочка
делает журнал устойчивым к подделке: если изменится хотя бы один байт, будет удалена строка или строки будут переставлены местами, цепочка разорвётся. verifyIntegrity() проходит по файлу и возвращает индекс первой записи с расхождением или null, если цепочка не нарушена. readAll() выдаёт записи потоково. Рекомендательная блокировка flock(LOCK_EX) на уровне процесса защищает критическую секцию “прочитать хвост, затем добавить”, поэтому параллельные процессы PHP, работающие с одним файлом, не перемешивают записи. Ограничение указано явно: это линейная хеш-цепочка, а не дерево Меркла по RFC 6962 (Request for Comments). Её достаточно для выявления подделки, но не для эффективных доказательств включения. Это указано в исходном коде. SiemEvent представляет типизированное событие с методом toCanonicalJson(). SiemEventSeverity и SiemEventType классифицируют его. CorrelationContext и CorrelationIdGenerator передают идентификатор корреляции между связанными событиями.
RenderReportBuilder, RenderReport, PilotReportAggregator и PilotSummary образуют интерфейс отчётности (@since 5.1.0). Агрегатор собирает объекты RenderReport и формирует PilotSummary, который экспортируется в виде массива, JSON или Markdown — в форме, пригодной для эксплуатационного разбора.
HsmAuditLogInterface / HsmAuditEvent фиксируют операции подписи с использованием HSM на уровне безопасности. MetricsCounterInterface, MetricsGaugeInterface, MetricsHistogramInterface и TraceSpanInterface задают формы метрик и трассировки. Реализации NoOp* предоставляют полноценный инертный резервный вариант, поэтому движок может выдавать метрики и интервалы трассировки без настроенного бэкенда.
Стабильность: экспериментальная. SIEM-журнал внутри помечается по циклам, а не имеет зафиксированный тег
@sinceсемантического версионирования (semver), а интерфейс отчётности имеет тег@since 5.1.0. Эти интерфейсы работоспособны и протестированы, но формы API (application programming interface) могут изменяться. Считайте формат журнала (канонический JSON + хеш-цепочка) стабильным контрактом, а PHP-API — ещё не устоявшимся.
Поверхность API
Заголовок раздела «Поверхность API»| Класс | Ключевые члены | Роль |
|---|---|---|
HashChainSiemEventLog | emit(SiemEvent), verifyIntegrity(): ?int, readAll(): Generator | Устойчивый к подделке SIEM-журнал с хеш-цепочкой |
SiemEvent | toCanonicalJson() | Типизированное событие SIEM |
SiemEventSeverity / SiemEventType (перечисления) | классификация | Классифицирует серьёзность и тип события |
CorrelationContext / CorrelationIdGenerator | сквозная передача корреляции | Передаёт корреляцию между связанными событиями |
RenderReportBuilder / RenderReport | сборка отчёта | Формирует отчёты об отдельных отрисовках (@since 5.1.0) |
PilotReportAggregator | addReport(), count(), getSummary(), toJson(), toMarkdown(), exportReportsJson() | Агрегирует отчёты об отрисовке (@since 5.1.0) |
PilotSummary | toArray(), toJson(), toMarkdown() | Готовит сводный вывод для эксплуатационного разбора (@since 5.1.0) |
HsmAuditLogInterface / HsmAuditEvent | запись аудита HSM | Фиксирует операции HSM в аудите |
NoOpSiemEventEmitter, NoOpMetricsCounter, NoOpTraceSpan, … | инертные резервные варианты | Предоставляет полноценные холостые реализации |
Выполните composer docs:generate-api-php -- --module=Observability, чтобы сформировать полную таблицу PHPDoc.
Пример кода — быстрый старт
Заголовок раздела «Пример кода — быстрый старт»Отправьте событие и проверьте целостность журнала.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Observability\Siem\HashChainSiemEventLog;use NextPDF\Observability\Siem\SiemEvent;
$log = new HashChainSiemEventLog('/var/log/nextpdf/siem.jsonl');$log->emit(new SiemEvent(/* type, severity, payload */));
$firstBroken = $log->verifyIntegrity();echo $firstBroken === null ? "SIEM chain intact.\n" : "Tamper detected at record {$firstBroken}.\n";Пример кода — промышленная эксплуатация
Заголовок раздела «Пример кода — промышленная эксплуатация»Оберните эмиттер так, чтобы сбой журналирования на горячем пути подписи обрабатывался локально и не превращался в неперехваченное исключение.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Observability\Siem\HashChainSiemEventLog;use NextPDF\Observability\Siem\Exception\SiemEmitterException;use NextPDF\Observability\Siem\SiemEvent;use Psr\Log\LoggerInterface;
final readonly class AuditedSiemSink{ public function __construct( private HashChainSiemEventLog $log, private LoggerInterface $fallback, ) {}
public function record(SiemEvent $event): void { try { $this->log->emit($event); } catch (SiemEmitterException $e) { // Do not let SIEM I/O abort the signing path; record and continue. $this->fallback->critical('SIEM emit failed; event not chained.', [ 'error' => $e->getMessage(), ]); } }}Граничные случаи и подводные камни
Заголовок раздела «Граничные случаи и подводные камни»emit()выбрасываетSiemEmitterExceptionпри ошибках записи. Вызывающий код на горячем пути подписи должен обернуть вызов и локально решить: подавить исключение, повторить попытку или прервать выполнение. Эмиттер не принимает решение за вас.verifyIntegrity()возвращает индекс первой нарушенной записи илиnull. Результат, отличный от null, означает, что начиная с этой точки журнал скомпрометирован. Не доверяйте записям с этого индекса и далее.- Рекомендательная блокировка
flockдействует на уровне процесса и в пределах одного файла. Для параллельной работы между узлами требуется внеполосный приёмник, например пересылка через syslog. Не считайте, что блокировка файла обеспечивает координацию между разными машинами. - Это линейная хеш-цепочка, а не дерево Меркла. Она обеспечивает выявление подделки, а не эффективные доказательства включения. Не позиционируйте её как такие доказательства.
- Резервные варианты
NoOp*являются полными и инертными. Не добавляйте ветвление по доступности бэкенда ради “экономии работы”. Холостая реализация и так не требует затрат.
Производительность
Заголовок раздела «Производительность»emit() читает хеш предыдущей записи и добавляет одну строку под блокировкой файла: O(1) на событие плюс блокировка. verifyIntegrity() имеет сложность O(n) по числу записей, поскольку проходит всю цепочку. Запускайте его по расписанию, а не на горячем пути. Агрегация отчётов линейна по числу отчётов. Профиль воспроизводимости — structural: события и отчёты содержат отметки времени и идентификаторы корреляции, поэтому два запуска различаются этими полями, тогда как структура цепочки остаётся детерминированной.
Замечания по безопасности
Заголовок раздела «Замечания по безопасности»SIEM-журнал является средством контроля безопасности. Его устойчивость к подделке зависит от защиты как самого файла журнала, так и шага проверки: храните файл в хранилище с контролем доступа, поддерживающем дозапись, запускайте verifyIntegrity() по расписанию и пересылайте записи по внеполосному каналу, чтобы компрометация узла не могла незаметно переписать историю. События могут содержать конфиденциальный контекст. Выполняйте принятую в проекте обязательную очистку данных для журнала до формирования события, а не после его включения в цепочку, поскольку перезапись после очистки разорвала бы цепочку. Журнал аудита HSM фиксирует операции подписи и сам по себе значим для безопасности. Применяйте к нему те же меры защиты. См. модель угроз движка в /modules/core/security/.
Соответствие
Заголовок раздела «Соответствие»Этот модуль не заявляет о нормативном соответствии спецификациям PDF. Он реализует механизмы целостности журналов и наблюдаемости, устройство которых согласуется с практиками управления журналами и проверки целостности из NIST SP 800-92. Связь с системой средств контроля задокументирована в исходном коде; это не привязанная к конкретному фрагменту цитата из PDF. Соответствие документов, которые создаёт движок, проверяется с помощью оракула и наборов эталонных файлов, описанных в /modules/core/conformance/.
См. также
Заголовок раздела «См. также»- Contracts / Observability — интерфейс поставщика услуг (SPI): структурированные исключения, Spectrum и политика деградации.
- Модуль Telemetry — мост OpenTelemetry для внешних бэкендов.
- Модуль Audit — экспортёр свидетельств соответствия, работающий в паре с SIEM-журналом.
- Модуль Security — операции подписи, фиксируемые журналом аудита HSM.
- Обзор соответствия