presseportale/config/logging.php
Kevin Adametz 5dfd622141 security: Andere Geräte abmelden, IP-weites Login-Limit, dauerhafte Sperrmarke, Passwortregeln, CSP im Melde-Modus
Restliche Phase 4 aus dem Sicherheitsaudit 07.10.2026:

- Sicherheitsseite: „Andere Geräte abmelden“ rotiert remember_token und
  beendet alle anderen Sessions, die aktuelle bleibt (nicht während einer
  Impersonation).
- LoginIpThrottle: 20 Fehlversuche je IP in 15 Minuten über alle Konten.
  Gezählt über das Failed-Event, damit Livewire-Login und Fortifys
  POST /login denselben Zähler teilen; Erfolg setzt ihn nicht zurück.
- Sperrmarke für Sessions in users.sessions_revoked_at_ms statt nur im
  Cache — übersteht cache:clear. Die alte Cache-Marke zählt übergangsweise
  mit und kann im nächsten Release entfallen.
- Neue und geänderte Passwörter: mindestens 12 Zeichen, in Produktion
  zusätzlich uncompromised() (HIBP, k-Anonymität). Bestehende bleiben gültig.
- Content-Security-Policy-Report-Only in Produktion; Meldungen über
  /csp-report nach storage/logs/csp-*.log, je Meldung höchstens einmal pro
  Stunde, ohne Query und tokenartige Pfadsegmente.

Migration: users.sessions_revoked_at_ms (users hat FULLTEXT, 25 MB, Sekunden).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:02:49 +00:00

201 lines
6.9 KiB
PHP

<?php
use Monolog\Handler\NullHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;
use Monolog\Processor\PsrLogMessageProcessor;
/**
* Themen-Channel: eine Tagesdatei je Thema, Rotation wie `daily`.
*
* @return array{driver: string, path: string, level: mixed, days: mixed, replace_placeholders: bool}
*/
$topicChannel = fn (string $topic): array => [
'driver' => 'daily',
'path' => storage_path("logs/{$topic}.log"),
'level' => env('LOG_LEVEL', 'debug'),
'days' => env('LOG_DAILY_DAYS', 14),
'replace_placeholders' => true,
];
return [
/*
|--------------------------------------------------------------------------
| Default Log Channel
|--------------------------------------------------------------------------
|
| This option defines the default log channel that is utilized to write
| messages to your logs. The value provided here should match one of
| the channels present in the list of "channels" configured below.
|
*/
'default' => env('LOG_CHANNEL', 'stack'),
/*
|--------------------------------------------------------------------------
| Deprecations Log Channel
|--------------------------------------------------------------------------
|
| This option controls the log channel that should be used to log warnings
| regarding deprecated PHP and library features. This allows you to get
| your application ready for upcoming major versions of dependencies.
|
*/
'deprecations' => [
'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),
'trace' => env('LOG_DEPRECATIONS_TRACE', false),
],
/*
|--------------------------------------------------------------------------
| Log Channels
|--------------------------------------------------------------------------
|
| Here you may configure the log channels for your application. Laravel
| utilizes the Monolog PHP logging library, which includes a variety
| of powerful log handlers and formatters that you're free to use.
|
| Available drivers: "single", "daily", "slack", "syslog",
| "errorlog", "monolog", "custom", "stack"
|
*/
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => explode(',', env('LOG_STACK', 'daily')),
'ignore_exceptions' => false,
],
'single' => [
'driver' => 'single',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'replace_placeholders' => true,
],
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'days' => env('LOG_DAILY_DAYS', 14),
'replace_placeholders' => true,
],
/*
|----------------------------------------------------------------------
| Themen-Channels (je Thema eine Tagesdatei)
|----------------------------------------------------------------------
|
| Fachliche Meldungen landen nicht im allgemeinen `laravel-*.log`,
| sondern über `Log::channel('…')` in einer eigenen Tagesdatei unter
| storage/logs/<thema>-YYYY-MM-DD.log. Rotation wie `daily`
| (LOG_DAILY_DAYS). Das allgemeine Log behält Exceptions, `report()`
| und alles, was keinem Thema zugeordnet ist.
|
| billing Stripe-Webhooks, Checkout, Tarifwechsel, STR-/MAN-
| Rechnungen, USt-ID, Erfüllung bezahlter Vorgänge
| ki KI-Klassifikation, Content-Score, Profil- und
| Vorprüfung, Auto-Veröffentlichung
| monitoring Betriebs-Alerts (OperationalAlert): fehlgeschlagene
| Scheduler-Tasks/Queue-Jobs, Mail-Breaker, Bounces
| market Kursdaten-Abruf (market:refresh)
| admin_slow langsame Admin-Requests (eigene Schwellen/Env-Werte)
|
*/
'billing' => $topicChannel('billing'),
'ki' => $topicChannel('ki'),
'monitoring' => $topicChannel('monitoring'),
'market' => $topicChannel('market'),
// CSP-Meldungen der Browser (Melde-Modus, CspReportController).
'csp' => $topicChannel('csp'),
'admin_slow' => [
'driver' => 'daily',
'path' => storage_path('logs/admin-slow.log'),
'level' => env('ADMIN_SLOW_REQUEST_LOG_LEVEL', 'warning'),
'days' => env('ADMIN_SLOW_REQUEST_LOG_DAYS', 14),
'replace_placeholders' => true,
],
/*
| Testsuite: phpunit.xml setzt LOG_CHANNEL=testing, und tests/TestCase.php
| biegt die Themen-Channels ebenfalls hierher um — Tests schreiben damit
| ausschließlich nach testing-YYYY-MM-DD.log und verwässern weder das
| allgemeine noch die Themen-Logs. Kurze Aufbewahrung, reine Diagnose.
*/
'testing' => [
'driver' => 'daily',
'path' => storage_path('logs/testing.log'),
'level' => env('LOG_LEVEL', 'debug'),
'days' => 3,
'replace_placeholders' => true,
],
'slack' => [
'driver' => 'slack',
'url' => env('LOG_SLACK_WEBHOOK_URL'),
'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'),
'emoji' => env('LOG_SLACK_EMOJI', ':boom:'),
'level' => env('LOG_LEVEL', 'critical'),
'replace_placeholders' => true,
],
'papertrail' => [
'driver' => 'monolog',
'level' => env('LOG_LEVEL', 'debug'),
'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class),
'handler_with' => [
'host' => env('PAPERTRAIL_URL'),
'port' => env('PAPERTRAIL_PORT'),
'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),
],
'processors' => [PsrLogMessageProcessor::class],
],
'stderr' => [
'driver' => 'monolog',
'level' => env('LOG_LEVEL', 'debug'),
'handler' => StreamHandler::class,
'formatter' => env('LOG_STDERR_FORMATTER'),
'with' => [
'stream' => 'php://stderr',
],
'processors' => [PsrLogMessageProcessor::class],
],
'syslog' => [
'driver' => 'syslog',
'level' => env('LOG_LEVEL', 'debug'),
'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER),
'replace_placeholders' => true,
],
'errorlog' => [
'driver' => 'errorlog',
'level' => env('LOG_LEVEL', 'debug'),
'replace_placeholders' => true,
],
'null' => [
'driver' => 'monolog',
'handler' => NullHandler::class,
],
'emergency' => [
'path' => storage_path('logs/laravel.log'),
],
],
];