Files
michaelschiemer/src/Framework/Exception/Security/XssAttemptException.php
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
2025-10-25 19:18:37 +02:00

366 lines
12 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Framework\Exception\Security;
use App\Framework\Exception\Core\SecurityErrorCode;
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: SecurityErrorCode::XSS_DETECTED
);
}
// === 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;
}
}