NIS2 Compliance
AuditChain's cryptographic hash chain mode (HasAuditTrail) provides tamper-evident logging, automated chain verification, and real-time alerting — capabilities that directly address cybersecurity audit requirements. These features align with the NIS2 Directive (EU 2022/2555), which requires essential and important entities to implement risk analysis, incident handling, and supply chain security measures under Article 21.
Article 21 Requirements and AuditChain
Incident Handling (Article 21(2)(b))
NIS2 requires organizations to detect, respond to, and report security incidents. AuditChain helps by providing:
- Immutable audit trail — Every change to your Eloquent models is recorded in a tamper-evident log. If a breach occurs, you have a reliable record of what was accessed or modified and when.
personal_data_accessedtracking — Each audit log entry records which personal data fields were involved, making it straightforward to assess the scope of a breach as required by GDPR Article 33 (which NIS2 references).- Read event capture — Enable
log_readsto track who accessed sensitive records, not just who modified them.
// config/audit-chain.php 'events' => [ 'log_reads' => true, ],
Risk Analysis and Security Policies (Article 21(2)(a))
Chain verification provides continuous assurance that your audit data has not been tampered with:
# Verify the entire chain php artisan audit:verify # Verify a specific model type php artisan audit:verify --type="App\Models\User" # Verify a specific record php artisan audit:verify --type="App\Models\User" --id=42
Automated Monitoring
Schedule regular chain verification and configure notifications so your team is alerted immediately if tampering is detected:
// routes/console.php Schedule::command('audit:verify --notify')->hourly();
When the --notify flag is used and verification fails, AuditChain sends alerts through the configured channels:
// config/audit-chain.php 'notifications' => [ 'channels' => ['mail', 'webhook'], 'mail_to' => [env('AUDIT_ALERT_EMAIL', 'security@example.com')], 'webhooks' => [ env('AUDIT_ALERT_WEBHOOK_1'), // Slack, Teams, Discord, or custom ], ],
Webhook payloads include both text and content keys for cross-platform compatibility with Slack, Microsoft Teams, Discord, and custom endpoints.
Supply Chain Security (Article 21(2)(d))
AuditChain supports a separate database connection for audit logs, isolating them from the main application database. This limits the blast radius if the application database is compromised:
// config/audit-chain.php 'connection' => 'audit', // dedicated DB connection
For maximum immutability, use a database user with INSERT and SELECT only on the audit table. Eloquent guards prevent modification at the application layer, but database-level restrictions ensure immutability even if the application itself is compromised.
Tamper Detection
The SHA-256 hash chain is AuditChain's core defense against tampering. Each audit log entry contains:
- A
hashcomputed from the audit data (event, values, user, IP, timestamp, and the previous hash) - A
prev_hashlinking it to the previous entry in the chain
Modifying, inserting, or deleting any entry in the chain breaks the link and is detected during verification. This provides the kind of tamper-evidence that NIS2 Article 21 expects from cybersecurity logging systems.
You can also verify the chain programmatically:
use GrayMatter\AuditChain\Services\AuditChainService; $result = app(AuditChainService::class)->verifyChain(); // ['valid' => true, 'checked' => 1500, 'errors' => []] if (! $result['valid']) { // Handle chain compromise -- alert security team, lock down system }
Recommended NIS2 Setup
For organizations subject to NIS2, we recommend the following configuration:
// config/audit-chain.php return [ // Isolate audit data on a separate connection 'connection' => 'audit', // Use queue to avoid blocking request lifecycle 'queue' => [ 'enabled' => true, 'connection' => null, 'queue' => 'audit', ], // Enable read tracking for sensitive models 'events' => [ 'log_reads' => true, ], // Retain logs for regulatory minimum (adjust per your jurisdiction) 'retention' => [ 'days' => 365, ], // Alert on chain compromise 'notifications' => [ 'channels' => ['mail', 'webhook'], 'mail_to' => ['security@example.com', 'dpo@example.com'], 'webhooks' => [ env('AUDIT_ALERT_WEBHOOK_1'), ], ], ];
And in your scheduler:
// routes/console.php Schedule::command('audit:verify --notify')->hourly(); Schedule::command('audit:prune --days=365')->daily();
Important: Set
AUDIT_CHAIN_SEEDto a random, secret value in your.envfile. The chain seed is used to compute the genesis hash. A predictable seed weakens the tamper-evidence guarantees that NIS2 compliance depends on.