shouldProcessCsrf($context)) { return $html; } if ($this->cacheMode) { // Cache-Modus: Ersetze echte Tokens mit Platzhaltern return $this->replaceTokensWithPlaceholders($html, $context); } else { // Render-Modus: Ersetze Platzhalter mit echten Tokens return $this->replacePlaceholdersWithTokens($html, $context); } } /** * Prüft ob das Template CSRF-Token-Processing benötigt */ private function shouldProcessCsrf(RenderContext $context): bool { // Check 1: Data enthält CSRF-Token if (isset($context->data['csrf_token']) || isset($context->data['_token'])) { return true; } // Check 2: Template-Name deutet auf Formulare hin $formKeywords = ['form', 'contact', 'login', 'register', 'checkout', 'admin']; foreach ($formKeywords as $keyword) { if (str_contains($context->template, $keyword)) { return true; } } return false; } /** * Cache-Modus: Ersetzt echte CSRF-Tokens mit Platzhaltern */ private function replaceTokensWithPlaceholders(string $html, RenderContext $context): string { $this->debugLog("Converting CSRF tokens to placeholders for caching"); // 1. Ersetze Template-Syntax CSRF-Aufrufe $html = $this->replaceTemplateCsrfCalls($html); // 2. Ersetze echte Token-Werte falls vorhanden if (isset($context->data['csrf_token'])) { $html = str_replace($context->data['csrf_token'], self::CSRF_PLACEHOLDER, $html); } if (isset($context->data['_token'])) { $html = str_replace($context->data['_token'], self::CSRF_PLACEHOLDER, $html); } // 3. Ersetze HTML-Pattern $html = $this->replaceHtmlCsrfPatterns($html); return $html; } /** * Render-Modus: Ersetzt Platzhalter mit echten CSRF-Tokens */ private function replacePlaceholdersWithTokens(string $html, RenderContext $context): string { $this->debugLog("Converting placeholders to fresh CSRF tokens"); $csrfToken = $this->getCsrfToken($context); // Ersetze alle Platzhalter-Types $replacements = [ self::CSRF_PLACEHOLDER => $csrfToken, self::META_PLACEHOLDER => $csrfToken, self::FIELD_PLACEHOLDER => $this->generateCsrfField($csrfToken), ]; return str_replace(array_keys($replacements), array_values($replacements), $html); } /** * Ersetzt Template-Syntax CSRF-Aufrufe mit Platzhaltern */ private function replaceTemplateCsrfCalls(string $html): string { $patterns = [ // {{ csrf_token() }} oder {{ csrf_token }} '/\{\{\s*csrf_token\(\s*\)\s*\}\}/' => self::CSRF_PLACEHOLDER, '/\{\{\s*csrf_token\s*\}\}/' => self::CSRF_PLACEHOLDER, // {!! csrf_token() !!} '/\{!!\s*csrf_token\(\s*\)\s*!!\}/' => self::CSRF_PLACEHOLDER, // {{ _token }} '/\{\{\s*_token\s*\}\}/' => self::CSRF_PLACEHOLDER, // @csrf Blade-Direktive '/@csrf/' => self::FIELD_PLACEHOLDER, // csrf_field() Helper '/\{\{\s*csrf_field\(\s*\)\s*\}\}/' => self::FIELD_PLACEHOLDER, '{!! csrf_field() !!}' => self::FIELD_PLACEHOLDER, ]; return preg_replace(array_keys($patterns), array_values($patterns), $html); } /** * Ersetzt HTML-CSRF-Patterns mit Platzhaltern */ private function replaceHtmlCsrfPatterns(string $html): string { // Hidden Input Fields mit CSRF-Token $html = preg_replace( '/]*name=["\']_token["\'][^>]*value=["\']([^"\']+)["\'][^>]*>/', '', $html ); // Meta Tags mit CSRF-Token $html = preg_replace( '/]*name=["\']csrf-token["\'][^>]*content=["\']([^"\']+)["\'][^>]*>/', '', $html ); return $html; } /** * Holt den aktuellen CSRF-Token */ private function getCsrfToken(RenderContext $context): string { // Priorität: Context-Daten > Generierter Token return $context->data['csrf_token'] ?? $context->data['_token'] ?? $this->generateFreshCsrfToken(); } /** * Generiert einen neuen CSRF-Token */ private function generateFreshCsrfToken(): string { // Integration mit deinem CSRF-System // Das könnte auch ein Service-Call sein return bin2hex(random_bytes(32)); } /** * Generiert ein komplettes CSRF-Hidden-Field */ private function generateCsrfField(string $token): string { return ''; } /** * Debug-Logging */ private function debugLog(string $message): void { // Debug logging removed for production // Use proper logger in production environment } /** * Factory-Methode für Cache-Modus */ public static function forCaching(bool $debugMode = false): self { return new self(cacheMode: true, debugMode: $debugMode); } /** * Factory-Methode für Render-Modus */ public static function forRendering(bool $debugMode = false): self { return new self(cacheMode: false, debugMode: $debugMode); } }