Enable Discovery debug logging for production troubleshooting

- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
2025-08-11 20:13:26 +02:00
parent 59fd3dd3b1
commit 55a330b223
3683 changed files with 2956207 additions and 16948 deletions

View File

@@ -0,0 +1,342 @@
<?php
declare(strict_types=1);
namespace App\Framework\Exception\Security;
use App\Framework\Exception\ErrorCode;
use App\Framework\Exception\ExceptionContext;
use App\Framework\Exception\FrameworkException;
/**
* Ausnahme für Path-Traversal-Angriffs-Versuche
*
* Verwendet OWASP-konforme Nachrichten für Path-Traversal-Detection
*/
final class PathTraversalAttemptException extends FrameworkException
{
/**
* @param string $clientIp Client-IP für Security-Tracking
* @param string $requestedPath Angeforderte Pfad
* @param string $pattern Erkanntes Path-Traversal-Pattern
* @param string $attackContext Kontext (file_access, url_parameter, etc.)
* @param \Throwable|null $previous Vorherige Ausnahme
*/
public function __construct(
public readonly string $clientIp,
public readonly string $requestedPath,
public readonly string $pattern,
public readonly string $attackContext = 'file_access',
?\Throwable $previous = null
) {
// OWASP-konforme Nachricht mit Platzhaltern
$message = "Client {$this->clientIp} attempted path traversal: {$this->requestedPath}";
$context = ExceptionContext::forOperation('security.path_traversal_detection', 'Security')
->withData([
'client_ip' => $this->clientIp,
'requested_path' => $this->requestedPath,
'pattern' => $this->pattern,
'context' => $this->attackContext,
'path_depth' => $this->calculateTraversalDepth(),
'event_identifier' => "security_path_traversal:{$this->clientIp}",
'category' => 'file_access',
'requires_alert' => true, // Path-Traversal-Versuche erfordern immer Alerts
])
->withMetadata([
'security_event' => true,
'owasp_compliant' => true,
'log_level' => 'ERROR',
'attack_type' => 'path_traversal',
'critical_security_event' => true,
]);
parent::__construct(
message: $message,
context: $context,
code: 400, // Bad Request
previous: $previous,
errorCode: ErrorCode::SECURITY_PATH_TRAVERSAL
);
}
// === Factory Methods für verschiedene Path-Traversal-Patterns ===
public static function dotDotSlash(string $clientIp, string $path): self
{
return new self($clientIp, $path, '../ pattern', 'file_access');
}
public static function dotDotBackslash(string $clientIp, string $path): self
{
return new self($clientIp, $path, '..\ pattern', 'file_access');
}
public static function encodedTraversal(string $clientIp, string $path): self
{
return new self($clientIp, $path, 'URL-encoded traversal', 'file_access');
}
public static function unicodeTraversal(string $clientIp, string $path): self
{
return new self($clientIp, $path, 'Unicode-encoded traversal', 'file_access');
}
public static function absolutePath(string $clientIp, string $path): self
{
return new self($clientIp, $path, 'Absolute path access', 'file_access');
}
public static function systemPath(string $clientIp, string $path): self
{
return new self($clientIp, $path, 'System directory access', 'system_access');
}
public static function configFileAccess(string $clientIp, string $path): self
{
return new self($clientIp, $path, 'Configuration file access', 'config_access');
}
/**
* Gibt OWASP-konforme Event-Daten zurück
*/
public function getSecurityEventData(): array
{
return [
'event_identifier' => "security_path_traversal:{$this->clientIp}",
'description' => "Client {$this->clientIp} attempted path traversal: {$this->requestedPath}",
'category' => 'file_access',
'log_level' => 'ERROR',
'requires_alert' => true,
'client_ip' => $this->clientIp,
'requested_path' => $this->requestedPath,
'pattern' => $this->pattern,
'context' => $this->attackContext,
'attack_severity' => $this->getAttackSeverity(),
];
}
/**
* Bestimmt Schweregrad des Path-Traversal-Angriffs
*/
public function getAttackSeverity(): string
{
// Systemverzeichnisse sind kritisch
$criticalPaths = ['/etc/', '/var/', '/usr/', '/sys/', '/proc/', 'C:\Windows', 'C:\System'];
foreach ($criticalPaths as $critical) {
if (str_contains($this->requestedPath, $critical)) {
return 'CRITICAL';
}
}
// Konfigurationsdateien sind hochriskant
$sensitiveFiles = ['.env', 'config', 'passwd', 'shadow', 'hosts', 'web.config'];
foreach ($sensitiveFiles as $sensitive) {
if (str_contains($this->requestedPath, $sensitive)) {
return 'HIGH';
}
}
// Deep traversal ist verdächtig
if ($this->calculateTraversalDepth() > 3) {
return 'HIGH';
}
return 'MEDIUM';
}
/**
* Berechnet die Tiefe des Traversal-Versuchs
*/
public function calculateTraversalDepth(): int
{
return substr_count($this->requestedPath, '../') + substr_count($this->requestedPath, '..\\');
}
/**
* Path-Traversal-Versuche erfordern immer Alerts
*/
public function requiresAlert(): bool
{
return true;
}
/**
* Prüft ob es ein automatisierter Angriff ist
*/
public function isAutomatedAttack(): bool
{
// Typische automatisierte Scanner-Patterns
$automatedPatterns = [
'../../../../../../../../etc/passwd',
'..\\..\\..\\..\\windows\\system32',
'%2e%2e%2f', // URL-encoded ../
'\x2e\x2e\x2f', // Hex-encoded
];
$lowerPath = strtolower($this->requestedPath);
foreach ($automatedPatterns as $pattern) {
if (str_contains($lowerPath, strtolower($pattern))) {
return true;
}
}
return false;
}
/**
* Analysiert das Path-Traversal-Pattern detailliert
*/
public function analyzePattern(): array
{
$analysis = [
'encoding_type' => 'none',
'target_os' => 'unknown',
'target_files' => [],
'traversal_depth' => $this->calculateTraversalDepth(),
'automation_detected' => $this->isAutomatedAttack(),
'evasion_techniques' => [],
];
// Encoding-Erkennung
if (str_contains($this->requestedPath, '%')) {
$analysis['encoding_type'] = 'url_encoded';
} elseif (str_contains($this->requestedPath, '\x')) {
$analysis['encoding_type'] = 'hex_encoded';
} elseif (preg_match('/\\u[0-9a-f]{4}/i', $this->requestedPath)) {
$analysis['encoding_type'] = 'unicode_encoded';
}
// OS-Erkennung
if (str_contains($this->requestedPath, '\\')) {
$analysis['target_os'] = 'windows';
} elseif (str_contains($this->requestedPath, '/')) {
$analysis['target_os'] = 'unix';
}
// Zieldateien identifizieren
$targetFiles = [
'passwd' => 'unix_password_file',
'shadow' => 'unix_shadow_file',
'hosts' => 'hosts_file',
'.env' => 'environment_file',
'config' => 'configuration_file',
'web.config' => 'iis_config',
'httpd.conf' => 'apache_config',
'nginx.conf' => 'nginx_config',
];
foreach ($targetFiles as $file => $description) {
if (str_contains(strtolower($this->requestedPath), $file)) {
$analysis['target_files'][] = $description;
}
}
// Evasion-Techniken
if (str_contains($this->requestedPath, './')) {
$analysis['evasion_techniques'][] = 'current_directory_reference';
}
if (preg_match('/\.{3,}/', $this->requestedPath)) {
$analysis['evasion_techniques'][] = 'multiple_dots';
}
if (str_contains($this->requestedPath, '//')) {
$analysis['evasion_techniques'][] = 'double_slash';
}
return $analysis;
}
/**
* Gibt benutzerfreundliche Fehlermeldung zurück (ohne Details zu verraten)
*/
public function getUserMessage(): string
{
return "Invalid file path. Access denied.";
}
/**
* Gibt spezifische Verteidigungsempfehlung zurück
*/
public function getDefenseRecommendation(): string
{
return match ($this->attackContext) {
'file_access' => 'Implement proper path validation, use allowlists, and restrict file access to specific directories.',
'system_access' => 'Block access to system directories, implement strict path validation, and use security contexts.',
'config_access' => 'Secure configuration files, implement access controls, and use environment variables.',
default => 'Implement comprehensive path validation and access controls.',
};
}
/**
* Generiert IOC (Indicator of Compromise) für Security-Teams
*/
public function generateIOC(): array
{
return [
'type' => 'path_traversal_attempt',
'source_ip' => $this->clientIp,
'requested_path' => $this->requestedPath,
'pattern' => $this->pattern,
'context' => $this->attackContext,
'severity' => $this->getAttackSeverity(),
'timestamp' => date('Y-m-d H:i:s'),
'automated' => $this->isAutomatedAttack(),
'analysis' => $this->analyzePattern(),
];
}
/**
* Prüft ob sofortige Gegenmaßnahmen erforderlich sind
*/
public function requiresImmediateAction(): bool
{
return in_array($this->getAttackSeverity(), ['HIGH', 'CRITICAL']) ||
$this->isAutomatedAttack() ||
$this->calculateTraversalDepth() > 5;
}
/**
* Gibt WAF-Regel-Vorschläge zurück
*/
public function getWafRuleSuggestions(): array
{
$rules = [
'Block requests containing ../ or ..\\ patterns',
'Block requests with URL-encoded path traversal sequences',
'Block access to sensitive file extensions (.env, .config, etc.)',
];
$analysis = $this->analyzePattern();
if ($analysis['encoding_type'] !== 'none') {
$rules[] = 'Implement URL decoding before path traversal detection';
}
if (! empty($analysis['target_files'])) {
$rules[] = 'Block access to system configuration files and password files';
}
if ($analysis['traversal_depth'] > 3) {
$rules[] = 'Limit maximum directory traversal depth';
}
return $rules;
}
/**
* Gibt sichere Alternative für File-Access vor
*/
public function getSecureAlternatives(): array
{
return [
'Use file IDs instead of file paths in URLs',
'Implement a file mapping table',
'Restrict file access to a specific directory',
'Use symbolic links instead of direct paths',
'Implement role-based file access controls',
'Validate file paths against an allowlist',
];
}
}

View File

@@ -0,0 +1,284 @@
<?php
declare(strict_types=1);
namespace App\Framework\Exception\Security;
use App\Framework\Exception\ErrorCode;
use App\Framework\Exception\ExceptionContext;
use App\Framework\Exception\FrameworkException;
/**
* Ausnahme für SQL-Injection-Versuche
*
* Verwendet OWASP-konforme Nachrichten für SQL-Injection-Detection
*/
final class SqlInjectionAttemptException extends FrameworkException
{
/**
* @param string $clientIp Client-IP für Security-Tracking
* @param string $field Betroffenes Feld/Parameter
* @param string $pattern Erkanntes SQL-Injection-Pattern
* @param string $originalValue Ursprünglicher Wert (sanitized)
* @param string $detectionMethod Erkennungsmethode (regex, heuristic, etc.)
* @param \Throwable|null $previous Vorherige Ausnahme
*/
public function __construct(
public readonly string $clientIp,
public readonly string $field,
public readonly string $pattern,
public readonly string $originalValue,
public readonly string $detectionMethod = 'pattern_match',
?\Throwable $previous = null
) {
// OWASP-konforme Nachricht mit Platzhaltern
$message = "Client {$this->clientIp} attempted SQL injection in field {$this->field}";
$context = ExceptionContext::forOperation('security.sql_injection_detection', 'Security')
->withData([
'client_ip' => $this->clientIp,
'field' => $this->field,
'pattern' => $this->pattern,
'detection_method' => $this->detectionMethod,
'value_length' => strlen($this->originalValue),
'event_identifier' => "security_sql_injection:{$this->clientIp},{$this->field}",
'category' => 'input_validation',
'requires_alert' => true, // SQL-Injection-Versuche erfordern immer Alerts
])
->withDebug([
'sanitized_value' => $this->sanitizeValueForLog($this->originalValue),
])
->withMetadata([
'security_event' => true,
'owasp_compliant' => true,
'log_level' => 'ERROR',
'attack_type' => 'sql_injection',
'critical_security_event' => true,
]);
parent::__construct(
message: $message,
context: $context,
code: 400, // Bad Request
previous: $previous,
errorCode: ErrorCode::SECURITY_SQL_INJECTION
);
}
// === Factory Methods für verschiedene SQL-Injection-Patterns ===
public static function unionSelect(string $clientIp, string $field, string $value): self
{
return new self($clientIp, $field, 'UNION SELECT', $value, 'union_detection');
}
public static function commentInjection(string $clientIp, string $field, string $value): self
{
return new self($clientIp, $field, 'SQL Comment (-- or /*)', $value, 'comment_detection');
}
public static function blindSqlInjection(string $clientIp, string $field, string $value): self
{
return new self($clientIp, $field, 'Blind SQL Injection', $value, 'blind_detection');
}
public static function timeBasedInjection(string $clientIp, string $field, string $value): self
{
return new self($clientIp, $field, 'Time-based SQL Injection', $value, 'time_based_detection');
}
public static function errorBasedInjection(string $clientIp, string $field, string $value): self
{
return new self($clientIp, $field, 'Error-based SQL Injection', $value, 'error_based_detection');
}
public static function booleanBasedInjection(string $clientIp, string $field, string $value): self
{
return new self($clientIp, $field, 'Boolean-based SQL Injection', $value, 'boolean_detection');
}
public static function stackedQueries(string $clientIp, string $field, string $value): self
{
return new self($clientIp, $field, 'Stacked Queries', $value, 'stacked_queries_detection');
}
/**
* Gibt OWASP-konforme Event-Daten zurück
*/
public function getSecurityEventData(): array
{
return [
'event_identifier' => "security_sql_injection:{$this->clientIp},{$this->field}",
'description' => "Client {$this->clientIp} attempted SQL injection in field {$this->field}",
'category' => 'input_validation',
'log_level' => 'ERROR',
'requires_alert' => true,
'client_ip' => $this->clientIp,
'field' => $this->field,
'pattern' => $this->pattern,
'detection_method' => $this->detectionMethod,
'attack_severity' => $this->getAttackSeverity(),
];
}
/**
* Bestimmt Schweregrad des Angriffs
*/
public function getAttackSeverity(): string
{
return match ($this->detectionMethod) {
'union_detection' => 'HIGH',
'stacked_queries_detection' => 'CRITICAL',
'error_based_detection' => 'HIGH',
'time_based_detection' => 'MEDIUM',
'blind_detection' => 'MEDIUM',
'boolean_detection' => 'MEDIUM',
'comment_detection' => 'LOW',
default => 'MEDIUM',
};
}
/**
* SQL-Injection-Versuche erfordern immer Alerts
*/
public function requiresAlert(): bool
{
return true;
}
/**
* Prüft ob es ein automatisierter Angriff ist
*/
public function isAutomatedAttack(): bool
{
// Heuristiken für automatisierte Angriffe
$automatedPatterns = [
'sqlmap',
'havij',
'pangolin',
'union select',
'order by',
'group by',
];
$lowerValue = strtolower($this->originalValue);
foreach ($automatedPatterns as $pattern) {
if (str_contains($lowerValue, $pattern)) {
return true;
}
}
return false;
}
/**
* Analysiert das SQL-Injection-Pattern
*/
public function analyzePattern(): array
{
$analysis = [
'type' => 'unknown',
'technique' => 'unknown',
'payload_type' => 'unknown',
'database_fingerprint' => 'unknown',
'automation_detected' => $this->isAutomatedAttack(),
];
$lowerValue = strtolower($this->originalValue);
// Typ-Erkennung
if (str_contains($lowerValue, 'union')) {
$analysis['type'] = 'union_based';
} elseif (str_contains($lowerValue, 'sleep(') || str_contains($lowerValue, 'waitfor')) {
$analysis['type'] = 'time_based';
} elseif (str_contains($lowerValue, '1=1') || str_contains($lowerValue, '1=0')) {
$analysis['type'] = 'boolean_based';
} elseif (str_contains($lowerValue, 'error') || str_contains($lowerValue, 'convert(')) {
$analysis['type'] = 'error_based';
}
// Technik-Erkennung
if (str_contains($lowerValue, '/*') || str_contains($lowerValue, '--')) {
$analysis['technique'] = 'comment_bypassing';
} elseif (str_contains($lowerValue, 'char(') || str_contains($lowerValue, 'ascii(')) {
$analysis['technique'] = 'encoding_bypassing';
} elseif (str_contains($lowerValue, ';')) {
$analysis['technique'] = 'stacked_queries';
}
// Database-Fingerprinting
if (str_contains($lowerValue, 'mysql') || str_contains($lowerValue, 'information_schema')) {
$analysis['database_fingerprint'] = 'mysql';
} elseif (str_contains($lowerValue, 'postgres') || str_contains($lowerValue, 'pg_')) {
$analysis['database_fingerprint'] = 'postgresql';
} elseif (str_contains($lowerValue, 'mssql') || str_contains($lowerValue, 'sys.')) {
$analysis['database_fingerprint'] = 'mssql';
} elseif (str_contains($lowerValue, 'oracle') || str_contains($lowerValue, 'dual')) {
$analysis['database_fingerprint'] = 'oracle';
}
return $analysis;
}
/**
* Gibt benutzerfreundliche Fehlermeldung zurück (ohne Details zu verraten)
*/
public function getUserMessage(): string
{
return "Invalid input detected. Please check your data and try again.";
}
/**
* Bereinigt Wert für sicheres Logging
*/
private function sanitizeValueForLog(string $value): string
{
// Begrenzen auf 100 Zeichen und entferne gefährliche Zeichen
$sanitized = substr($value, 0, 100);
$sanitized = preg_replace('/[<>"\']/', '*', $sanitized);
$sanitized = preg_replace('/\s+/', ' ', $sanitized);
return trim($sanitized);
}
/**
* Gibt Empfehlung für Verteidigung zurück
*/
public function getDefenseRecommendation(): string
{
return match ($this->detectionMethod) {
'union_detection' => 'Implement parameterized queries and input validation.',
'stacked_queries_detection' => 'Disable multiple statements and use stored procedures.',
'error_based_detection' => 'Implement proper error handling and logging.',
'time_based_detection' => 'Add request timeouts and rate limiting.',
'blind_detection' => 'Implement comprehensive input validation and WAF rules.',
default => 'Use parameterized queries, input validation, and proper escaping.',
};
}
/**
* Generiert IOC (Indicator of Compromise) für Security-Teams
*/
public function generateIOC(): array
{
return [
'type' => 'sql_injection_attempt',
'source_ip' => $this->clientIp,
'target_field' => $this->field,
'pattern' => $this->pattern,
'detection_method' => $this->detectionMethod,
'severity' => $this->getAttackSeverity(),
'timestamp' => date('Y-m-d H:i:s'),
'automated' => $this->isAutomatedAttack(),
'analysis' => $this->analyzePattern(),
];
}
/**
* Prüft ob sofortige Gegenmaßnahmen erforderlich sind
*/
public function requiresImmediateAction(): bool
{
return in_array($this->getAttackSeverity(), ['HIGH', 'CRITICAL']) || $this->isAutomatedAttack();
}
}

View File

@@ -0,0 +1,365 @@
<?php
declare(strict_types=1);
namespace App\Framework\Exception\Security;
use App\Framework\Exception\ErrorCode;
use App\Framework\Exception\ExceptionContext;
use App\Framework\Exception\FrameworkException;
/**
* Ausnahme für XSS-Angriffs-Versuche
*
* Verwendet OWASP-konforme Nachrichten für XSS-Detection
*/
final class XssAttemptException extends FrameworkException
{
/**
* @param string $clientIp Client-IP für Security-Tracking
* @param string $field Betroffenes Feld/Parameter
* @param string $pattern Erkanntes XSS-Pattern
* @param string $originalValue Ursprünglicher Wert (sanitized)
* @param string $xssType Art des XSS (reflected, stored, dom)
* @param \Throwable|null $previous Vorherige Ausnahme
*/
public function __construct(
public readonly string $clientIp,
public readonly string $field,
public readonly string $pattern,
public readonly string $originalValue,
public readonly string $xssType = 'reflected',
?\Throwable $previous = null
) {
// OWASP-konforme Nachricht mit Platzhaltern
$message = "Client {$this->clientIp} attempted XSS attack in field {$this->field}";
$context = ExceptionContext::forOperation('security.xss_detection', 'Security')
->withData([
'client_ip' => $this->clientIp,
'field' => $this->field,
'pattern' => $this->pattern,
'xss_type' => $this->xssType,
'value_length' => strlen($this->originalValue),
'event_identifier' => "security_xss_attempt:{$this->clientIp},{$this->field}",
'category' => 'input_validation',
'requires_alert' => true, // XSS-Versuche erfordern immer Alerts
])
->withDebug([
'sanitized_value' => $this->sanitizeValueForLog($this->originalValue),
])
->withMetadata([
'security_event' => true,
'owasp_compliant' => true,
'log_level' => 'ERROR',
'attack_type' => 'xss',
'critical_security_event' => true,
]);
parent::__construct(
message: $message,
context: $context,
code: 400, // Bad Request
previous: $previous,
errorCode: ErrorCode::SECURITY_XSS_ATTEMPT
);
}
// === Factory Methods für verschiedene XSS-Patterns ===
public static function scriptTag(string $clientIp, string $field, string $value): self
{
return new self($clientIp, $field, '<script> tag injection', $value, 'reflected');
}
public static function onEventHandler(string $clientIp, string $field, string $value): self
{
return new self($clientIp, $field, 'Event handler injection (onclick, onload, etc.)', $value, 'reflected');
}
public static function javascriptProtocol(string $clientIp, string $field, string $value): self
{
return new self($clientIp, $field, 'javascript: protocol injection', $value, 'reflected');
}
public static function htmlInjection(string $clientIp, string $field, string $value): self
{
return new self($clientIp, $field, 'HTML tag injection', $value, 'reflected');
}
public static function domBasedXss(string $clientIp, string $field, string $value): self
{
return new self($clientIp, $field, 'DOM-based XSS pattern', $value, 'dom');
}
public static function storedXss(string $clientIp, string $field, string $value): self
{
return new self($clientIp, $field, 'Stored XSS pattern', $value, 'stored');
}
public static function cssInjection(string $clientIp, string $field, string $value): self
{
return new self($clientIp, $field, 'CSS injection with expression()', $value, 'reflected');
}
public static function svgXss(string $clientIp, string $field, string $value): self
{
return new self($clientIp, $field, 'SVG-based XSS injection', $value, 'reflected');
}
/**
* Gibt OWASP-konforme Event-Daten zurück
*/
public function getSecurityEventData(): array
{
return [
'event_identifier' => "security_xss_attempt:{$this->clientIp},{$this->field}",
'description' => "Client {$this->clientIp} attempted XSS attack in field {$this->field}",
'category' => 'input_validation',
'log_level' => 'ERROR',
'requires_alert' => true,
'client_ip' => $this->clientIp,
'field' => $this->field,
'pattern' => $this->pattern,
'xss_type' => $this->xssType,
'attack_severity' => $this->getAttackSeverity(),
];
}
/**
* Bestimmt Schweregrad des XSS-Angriffs
*/
public function getAttackSeverity(): string
{
return match ($this->xssType) {
'stored' => 'CRITICAL', // Stored XSS ist am gefährlichsten
'dom' => 'HIGH', // DOM-based XSS ist schwer zu erkennen
'reflected' => 'MEDIUM', // Reflected XSS ist häufig aber weniger persistent
default => 'MEDIUM',
};
}
/**
* XSS-Versuche erfordern immer Alerts
*/
public function requiresAlert(): bool
{
return true;
}
/**
* Prüft ob es ein automatisierter Angriff ist
*/
public function isAutomatedAttack(): bool
{
$automatedPatterns = [
'alert(',
'prompt(',
'confirm(',
'document.cookie',
'xss',
'<svg',
'javascript:',
'onerror=',
'onload=',
];
$lowerValue = strtolower($this->originalValue);
foreach ($automatedPatterns as $pattern) {
if (str_contains($lowerValue, $pattern)) {
return true;
}
}
return false;
}
/**
* Analysiert das XSS-Pattern detailliert
*/
public function analyzePattern(): array
{
$analysis = [
'vector_type' => 'unknown',
'payload_complexity' => 'low',
'encoding_used' => false,
'obfuscation_detected' => false,
'automation_detected' => $this->isAutomatedAttack(),
'potential_impact' => 'low',
];
$lowerValue = strtolower($this->originalValue);
// Vector-Typ-Erkennung
if (str_contains($lowerValue, '<script')) {
$analysis['vector_type'] = 'script_tag';
} elseif (str_contains($lowerValue, 'on') && preg_match('/on\w+\s*=/', $lowerValue)) {
$analysis['vector_type'] = 'event_handler';
} elseif (str_contains($lowerValue, 'javascript:')) {
$analysis['vector_type'] = 'javascript_protocol';
} elseif (str_contains($lowerValue, '<svg') || str_contains($lowerValue, '<embed')) {
$analysis['vector_type'] = 'svg_embed';
} elseif (str_contains($lowerValue, 'expression(')) {
$analysis['vector_type'] = 'css_expression';
}
// Komplexität bewerten
if (strlen($this->originalValue) > 100) {
$analysis['payload_complexity'] = 'high';
} elseif (strlen($this->originalValue) > 50) {
$analysis['payload_complexity'] = 'medium';
}
// Encoding-Erkennung
if (str_contains($this->originalValue, '%') || str_contains($this->originalValue, '&#')) {
$analysis['encoding_used'] = true;
}
// Obfuskierung-Erkennung
if (preg_match('/String\.fromCharCode|eval\(|unescape\(/', $this->originalValue)) {
$analysis['obfuscation_detected'] = true;
$analysis['payload_complexity'] = 'high';
}
// Impact-Bewertung
if (str_contains($lowerValue, 'cookie') || str_contains($lowerValue, 'document')) {
$analysis['potential_impact'] = 'high';
} elseif (str_contains($lowerValue, 'alert') || str_contains($lowerValue, 'prompt')) {
$analysis['potential_impact'] = 'medium';
}
return $analysis;
}
/**
* Gibt benutzerfreundliche Fehlermeldung zurück (ohne Details zu verraten)
*/
public function getUserMessage(): string
{
return "Invalid input detected. Please check your data and try again.";
}
/**
* Bereinigt Wert für sicheres Logging
*/
private function sanitizeValueForLog(string $value): string
{
// HTML-Entities kodieren und auf 100 Zeichen begrenzen
$sanitized = htmlspecialchars(substr($value, 0, 100), ENT_QUOTES, 'UTF-8');
// Zusätzliche Bereinigung für Logs
$sanitized = preg_replace('/\s+/', ' ', $sanitized);
return trim($sanitized);
}
/**
* Gibt spezifische Verteidigungsempfehlung zurück
*/
public function getDefenseRecommendation(): string
{
return match ($this->xssType) {
'stored' => 'Implement output encoding, Content Security Policy, and input validation.',
'dom' => 'Use safe JavaScript APIs, validate DOM manipulation, implement CSP.',
'reflected' => 'Implement output encoding, input validation, and Content Security Policy.',
default => 'Use output encoding, input validation, and Content Security Policy.',
};
}
/**
* Generiert Content Security Policy Empfehlungen
*/
public function getCspRecommendations(): array
{
$baseCSP = [
"default-src 'self'",
"script-src 'self'",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data:",
"connect-src 'self'",
"font-src 'self'",
"object-src 'none'",
"frame-src 'none'",
];
$analysis = $this->analyzePattern();
// Verschärfungen basierend auf Angriffsmuster
if ($analysis['vector_type'] === 'script_tag') {
$baseCSP[] = "script-src 'self' 'nonce-{random}'"; // Nonce-basierte Scripts
}
if ($analysis['vector_type'] === 'css_expression') {
$baseCSP[] = "style-src 'self'"; // Entferne unsafe-inline
}
return $baseCSP;
}
/**
* Generiert IOC (Indicator of Compromise) für Security-Teams
*/
public function generateIOC(): array
{
return [
'type' => 'xss_attempt',
'source_ip' => $this->clientIp,
'target_field' => $this->field,
'pattern' => $this->pattern,
'xss_type' => $this->xssType,
'severity' => $this->getAttackSeverity(),
'timestamp' => date('Y-m-d H:i:s'),
'automated' => $this->isAutomatedAttack(),
'analysis' => $this->analyzePattern(),
];
}
/**
* Prüft ob sofortige Gegenmaßnahmen erforderlich sind
*/
public function requiresImmediateAction(): bool
{
return $this->xssType === 'stored' ||
$this->getAttackSeverity() === 'CRITICAL' ||
$this->isAutomatedAttack();
}
/**
* Gibt WAF (Web Application Firewall) Regel-Vorschläge zurück
*/
public function getWafRuleSuggestions(): array
{
$rules = [];
$analysis = $this->analyzePattern();
switch ($analysis['vector_type']) {
case 'script_tag':
$rules[] = 'Block requests containing <script tags in input fields';
break;
case 'event_handler':
$rules[] = 'Block requests containing on* event handlers in input fields';
break;
case 'javascript_protocol':
$rules[] = 'Block requests containing javascript: protocol in input fields';
break;
case 'svg_embed':
$rules[] = 'Block or sanitize SVG/embed tags in user input';
break;
}
if ($analysis['encoding_used']) {
$rules[] = 'Implement URL decoding before XSS detection';
}
if ($analysis['obfuscation_detected']) {
$rules[] = 'Implement advanced obfuscation detection rules';
}
return $rules;
}
}