Przejdź do głównej zawartości

Obserwowalność: dziennik SIEM z łańcuchem haszy i raportowanie renderowania

Moduł Observability udostępnia implementację używaną w czasie działania: dziennik zdarzeń zarządzania informacjami i zdarzeniami bezpieczeństwa (SIEM), który wykrywa manipulacje i opiera się na łańcuchu haszy, agregację raportów renderowania i raportów pilotażowych, dziennik audytu sprzętowego modułu bezpieczeństwa (HSM) oraz kompletne puste implementacje metryk i śladów, dzięki czemu wywołania instrumentacji są zawsze dostępne.

Jedna kanoniczna strona na zagadnienie. Kontrakty obserwowalności — ContextAwareExceptionInterface, SpectrumInterface, JobNotificationInterface oraz wyliczenie DegradationPolicy — są udokumentowane na stronie Contracts / Observability. Ta strona dokumentuje konkretną implementację używaną w czasie działania. Strony są komplementarne, a nie zduplikowane: sięgnij do strony kontraktów, gdy potrzebujesz interfejsu dostawcy usług (SPI), i do tej strony dla dziennika SIEM, raportowania oraz powierzchni audytu.

Okno terminala
composer require nextpdf/core:^3

Ten moduł przekształca informacje o stanie silnika w czasie działania w trwałe, weryfikowalne dane wyjściowe.

HashChainSiemEventLog to powierzchnia o znaczeniu bezpieczeństwa. Implementuje kontrakt SiemEventEmitter i zapisuje dziennik w formacie JavaScript Object Notation (JSON) Lines, w którym hasz każdego rekordu jest obliczany jako SHA-256(prev_hash_bytes || canonical_event_bytes). Ten liniowy łańcuch haszy sprawia, że dziennik wykrywa manipulacje: jeśli zmieni się dowolny bajt, zostanie usunięty wiersz albo zmieni się kolejność wierszy, łańcuch zostaje przerwany. verifyIntegrity() przechodzi przez plik i zwraca indeks pierwszego niespójnego rekordu albo null, gdy łańcuch jest nienaruszony. readAll() strumieniuje rekordy. Blokada doradcza flock(LOCK_EX) dla danego procesu chroni sekcję krytyczną „odczyt końcówki, a następnie dopisanie”, dzięki czemu współbieżne procesy PHP korzystające z tego samego pliku nie przeplatają rekordów. Ograniczenie jest jawne: to liniowy łańcuch haszy, a nie drzewo Merkle z Request for Comments (RFC) 6962. Wystarcza do wykrywania manipulacji, lecz nie do wydajnych dowodów przynależności. Tak wynika z kodu źródłowego. SiemEvent przenosi typowane zdarzenie z metodą toCanonicalJson(). SiemEventSeverity i SiemEventType je klasyfikują. CorrelationContext i CorrelationIdGenerator przekazują identyfikator korelacji pomiędzy powiązanymi zdarzeniami.

RenderReportBuilder, RenderReport, PilotReportAggregator oraz PilotSummary tworzą powierzchnię raportowania (@since 5.1.0). Agregator zbiera obiekty RenderReport i tworzy PilotSummary, które można wyrenderować jako tablicę, JSON albo Markdown w postaci nadającej się do przeglądu operacyjnego.

HsmAuditLogInterface / HsmAuditEvent rejestrują operacje podpisywania obsługiwane przez HSM na potrzeby warstwy bezpieczeństwa. Interfejsy MetricsCounterInterface, MetricsGaugeInterface, MetricsHistogramInterface oraz TraceSpanInterface definiują strukturę metryk i śladów. Implementacje NoOp* zapewniają kompletną, bierną implementację zastępczą, dzięki czemu silnik może emitować metryki i przedziały śladów bez skonfigurowanego zaplecza.

Stabilność: eksperymentalna. Dziennik SIEM jest wewnętrznie oznaczany cyklem, zamiast przenosić zamrożoną adnotację @since wersjonowania semantycznego (semver), a powierzchnia raportowania jest oznaczona @since 5.1.0. Powierzchnie są funkcjonalne i przetestowane, ale kształty interfejsu programowania aplikacji (API) mogą się zmieniać. Traktuj format dziennika (kanoniczny JSON + łańcuch haszy) jako stabilny kontrakt, a interfejs PHP API jako wciąż ustalający się.

KlasaKluczowe składoweRola
HashChainSiemEventLogemit(SiemEvent), verifyIntegrity(): ?int, readAll(): GeneratorDziennik SIEM wykrywający manipulacje i oparty na łańcuchu haszy
SiemEventtoCanonicalJson()Typowane zdarzenie SIEM
SiemEventSeverity / SiemEventType (wyliczenia)klasyfikacjaKlasyfikuje istotność i typ zdarzenia
CorrelationContext / CorrelationIdGeneratorprzekazywanie korelacjiPrzenosi korelację między powiązanymi zdarzeniami
RenderReportBuilder / RenderReportskładanie raportuBuduje raporty dla pojedynczych renderowań (@since 5.1.0)
PilotReportAggregatoraddReport(), count(), getSummary(), toJson(), toMarkdown(), exportReportsJson()Agreguje raporty renderowania (@since 5.1.0)
PilotSummarytoArray(), toJson(), toMarkdown()Podsumowuje dane wyjściowe przeglądu operacyjnego (@since 5.1.0)
HsmAuditLogInterface / HsmAuditEventRekord audytu HSMRejestruje audyt operacji HSM
NoOpSiemEventEmitter, NoOpMetricsCounter, NoOpTraceSpan, …bierne implementacje zastępczeZapewniają kompletne puste implementacje

Uruchom composer docs:generate-api-php -- --module=Observability, aby wygenerować pełną tabelę PHPDoc.

Wyemituj zdarzenie i zweryfikuj integralność dziennika.

<?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";

Opakuj emiter tak, aby awaria zapisu do dziennika na gorącej ścieżce podpisywania była obsługiwana lokalnie, zamiast kończyć się nieprzechwyconym wyjątkiem.

<?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() rzuca wyjątek SiemEmitterException przy błędach zapisu. Kod wywołujący na gorącej ścieżce podpisywania musi go opakować i lokalnie zdecydować, czy zignorować błąd, ponowić próbę, czy przerwać. Emiter nie podejmuje tej decyzji za Ciebie.
  • verifyIntegrity() zwraca indeks pierwszego uszkodzonego rekordu albo null. Wynik różny od null oznacza, że dziennik jest naruszony od tego miejsca. Nie ufaj rekordom od tego punktu włącznie.
  • Doradcza blokada flock działa w obrębie procesu i tego samego pliku. Współbieżność między hostami wymaga kanału poza pasmem, takiego jak przekazywanie syslog. Nie zakładaj, że blokada pliku koordynuje pracę między maszynami.
  • To liniowy łańcuch haszy, a nie drzewo Merkle. Zapewnia wykrywanie manipulacji, a nie wydajne dowody przynależności. Nie reklamuj go jako tego drugiego.
  • Implementacje zastępcze NoOp* są kompletne i bierne. Nie rozgałęziaj kodu w zależności od dostępności zaplecza, aby „zaoszczędzić pracę”. Pusta operacja i tak nic nie kosztuje.

emit() odczytuje hasz poprzedniego rekordu i dopisuje jeden wiersz pod blokadą pliku: O(1) na zdarzenie plus blokada. verifyIntegrity() ma złożoność O(n) względem liczby rekordów, ponieważ przechodzi przez cały łańcuch. Uruchamiaj ją według harmonogramu, a nie na gorącej ścieżce. Agregacja raportowania jest liniowa względem liczby raportów. Profil odtwarzalności jest structural: zdarzenia i raporty zawierają znaczniki czasu oraz identyfikatory korelacji, więc dwa uruchomienia różnią się w tych polach, podczas gdy struktura łańcucha pozostaje deterministyczna.

Dziennik SIEM jest mechanizmem bezpieczeństwa. Jego zdolność wykrywania manipulacji zależy od ochrony zarówno pliku dziennika, jak i kroku weryfikacji: przechowuj plik na pamięci masowej przystosowanej do dopisywania i objętej kontrolą dostępu, uruchamiaj verifyIntegrity() według harmonogramu i przekazuj rekordy poza pasmem, aby naruszenie hosta nie mogło po cichu przepisać historii. Zdarzenia mogą przenosić poufny kontekst. Stosuj projektowe zasady czyszczenia dzienników przed utworzeniem zdarzenia, a nie po dołączeniu go do łańcucha, ponieważ czyszczenie wpisu po fakcie przerwałoby łańcuch. Dziennik audytu HSM rejestruje operacje podpisywania i sam jest istotny dla bezpieczeństwa. Stosuj wobec niego te same zabezpieczenia. Zobacz model zagrożeń silnika w /modules/core/security/.

Ten moduł nie formułuje żadnego normatywnego twierdzenia dotyczącego specyfikacji PDF. Implementuje mechanizmy integralności dzienników i obserwowalności, których projekt jest zgodny z praktykami zarządzania dziennikami i weryfikacji integralności opisanymi w NIST SP 800-92. Zgodność z tymi ramami kontrolnymi jest udokumentowana w kodzie źródłowym; nie jest to odwołanie przypięte do konkretnego fragmentu specyfikacji PDF. Zgodność dokumentów, które silnik wytwarza, jest walidowana przez wyrocznię i zestawy wzorcowe opisane w /modules/core/conformance/.