getContent(); if (! config('security.csp.report_only') || $body === '' || strlen($body) > self::MAX_BYTES) { return response()->noContent(); } $report = json_decode($body, true)['csp-report'] ?? null; if (! is_array($report)) { return response()->noContent(); } $entry = [ 'directive' => mb_substr((string) ($report['effective-directive'] ?? $report['violated-directive'] ?? ''), 0, 60), 'blocked' => $this->scrub($report['blocked-uri'] ?? ''), 'document' => $this->scrub($report['document-uri'] ?? ''), 'source' => $this->scrub($report['source-file'] ?? ''), 'line' => (int) ($report['line-number'] ?? 0), 'sample' => mb_substr((string) ($report['script-sample'] ?? ''), 0, 40), ]; if (Cache::add('csp-report.'.sha1(json_encode($entry)), true, now()->addHour())) { Log::channel('csp')->warning('CSP-Verstoß (nur gemeldet)', $entry); } return response()->noContent(); } private function scrub(mixed $value): string { $value = mb_substr(is_string($value) ? $value : '', 0, 500); $parts = parse_url($value); // Schlüsselwörter wie „inline“, „eval“, „data“ unverändert. if (! is_array($parts) || empty($parts['host'])) { return mb_substr(strtok($value, '?#') ?: '', 0, 60); } $path = preg_replace('#/[A-Za-z0-9_-]{32,}(?=/|$)#', '/[Filtered]', $parts['path'] ?? ''); return mb_substr(($parts['scheme'] ?? 'https').'://'.$parts['host'].$path, 0, 200); } }