Files
michaelschiemer/src/Application/Security/WafOWASPEventBridge.php
Michael Schiemer 55a330b223 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
2025-08-11 20:13:26 +02:00

347 lines
14 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Application\Security;
use App\Application\Security\Events\Auth\{
AuthenticationFailedEvent
};
use App\Application\Security\Events\Input\{
InputValidationFailureEvent,
MaliciousInputDetectedEvent,
SqlInjectionAttemptEvent,
XssAttemptEvent
};
use App\Application\Security\Events\Network\SuspiciousNetworkActivityEvent;
use App\Application\Security\Events\System\SystemAnomalyEvent;
use App\Application\Security\ValueObjects\{
OWASPEventIdentifier,
OWASPLogLevel,
RequestContext,
SecurityContext
};
use App\Framework\Waf\DetectionCategory;
use App\Framework\Waf\DetectionSeverity;
use App\Framework\Waf\ValueObjects\Detection;
/**
* WAF-OWASP Event Bridge
*
* Consolidates the WAF Detection system with the existing OWASP Security Event framework
* to eliminate duplication and provide unified security event handling.
*/
final class WafOWASPEventBridge
{
public function __construct(
private readonly OWASPSecurityEventFactory $eventFactory,
private readonly OWASPSecurityEventLogger $eventLogger
) {
}
/**
* Convert WAF Detection to OWASP Security Event and log it
*/
public function processWafDetection(
Detection $detection,
SecurityContext $securityContext,
RequestContext $requestContext
): OWASPSecurityEvent {
$owaspEvent = $this->convertDetectionToOWASPEvent($detection, $requestContext);
// Log using existing OWASP logger
$logFormat = $this->eventFactory->createFromDetection(
$detection,
$owaspEvent,
$securityContext,
$requestContext
);
$this->eventLogger->log($logFormat);
return $owaspEvent;
}
/**
* Convert WAF Detection to appropriate OWASP Security Event
*/
public function convertDetectionToOWASPEvent(
Detection $detection,
RequestContext $requestContext
): OWASPSecurityEvent {
return match ($detection->category) {
DetectionCategory::SQL_INJECTION => $this->createSqlInjectionEvent($detection, $requestContext),
DetectionCategory::XSS => $this->createXssEvent($detection, $requestContext),
DetectionCategory::INJECTION,
DetectionCategory::COMMAND_INJECTION,
DetectionCategory::LDAP_INJECTION,
DetectionCategory::XPATH_INJECTION,
DetectionCategory::NOSQL_INJECTION => $this->createMaliciousInputEvent($detection, $requestContext),
DetectionCategory::BRUTE_FORCE,
DetectionCategory::CREDENTIAL_STUFFING,
DetectionCategory::AUTHENTICATION_BYPASS => $this->createAuthenticationFailedEvent($detection, $requestContext),
DetectionCategory::SUSPICIOUS_IP,
DetectionCategory::MALICIOUS_BOT,
DetectionCategory::DOS_ATTACK,
DetectionCategory::DDOS_ATTACK => $this->createSuspiciousNetworkActivityEvent($detection, $requestContext),
DetectionCategory::RATE_LIMIT_VIOLATION,
DetectionCategory::ANOMALOUS_BEHAVIOR,
DetectionCategory::SUSPICIOUS_USER_AGENT => $this->createSystemAnomalyEvent($detection, $requestContext),
default => $this->createGenericInputValidationEvent($detection, $requestContext)
};
}
/**
* Create SQL Injection OWASP event from WAF detection
*/
private function createSqlInjectionEvent(Detection $detection, RequestContext $requestContext): SqlInjectionAttemptEvent
{
$payload = $detection->payload?->getSample() ?? $detection->message;
$targetField = $detection->location ?? 'unknown_field';
$detectionMethod = "WAF Rule {($detection->ruleId?->value) ?? 'generic'}";
return new SqlInjectionAttemptEvent(
attackPayload: $payload,
targetField: $targetField,
detectionMethod: $detectionMethod,
email: $requestContext->getUserEmail()
);
}
/**
* Create XSS OWASP event from WAF detection
*/
private function createXssEvent(Detection $detection, RequestContext $requestContext): XssAttemptEvent
{
$payload = $detection->payload?->getSample() ?? $detection->message;
$targetField = $detection->location ?? 'unknown_field';
$xssType = $this->determineXssType($payload);
return new XssAttemptEvent(
attackPayload: $payload,
targetField: $targetField,
xssType: $xssType,
email: $requestContext->getUserEmail()
);
}
/**
* Create Malicious Input OWASP event from WAF detection
*/
private function createMaliciousInputEvent(Detection $detection, RequestContext $requestContext): MaliciousInputDetectedEvent
{
$payload = $detection->payload?->getSample() ?? $detection->message;
$inputType = $this->mapDetectionCategoryToInputType($detection->category);
return new MaliciousInputDetectedEvent(
inputPayload: $payload,
inputType: $inputType,
detectionMethod: "WAF Rule {($detection->ruleId?->value) ?? 'generic'}",
email: $requestContext->getUserEmail()
);
}
/**
* Create Authentication Failed OWASP event from WAF detection
*/
private function createAuthenticationFailedEvent(Detection $detection, RequestContext $requestContext): AuthenticationFailedEvent
{
$attackType = $this->mapDetectionCategoryToAttackType($detection->category);
$email = $requestContext->getUserEmail() ?? 'anonymous@waf.detection';
return new AuthenticationFailedEvent(
email: $email,
reason: $attackType,
failedAttempts: 1
);
}
/**
* Create Suspicious Network Activity OWASP event from WAF detection
*/
private function createSuspiciousNetworkActivityEvent(Detection $detection, RequestContext $requestContext): SuspiciousNetworkActivityEvent
{
$activityType = $this->mapDetectionCategoryToActivityType($detection->category);
return new SuspiciousNetworkActivityEvent(
sourceIp: $requestContext->getClientIp(),
activityType: $activityType,
requestCount: 1, // WAF detections are typically single requests
timeWindow: '1 minute',
email: $requestContext->getUserEmail()
);
}
/**
* Create System Anomaly OWASP event from WAF detection
*/
private function createSystemAnomalyEvent(Detection $detection, RequestContext $requestContext): SystemAnomalyEvent
{
$anomalyType = $this->mapDetectionCategoryToAnomalyType($detection->category);
$metrics = [
'threat_score' => $detection->getThreatScore()->getValue(),
'confidence' => $detection->confidence?->getValue(),
'location' => $detection->location,
'client_ip' => $requestContext->getClientIp(),
'rule_id' => $detection->ruleId?->value,
];
return new SystemAnomalyEvent(
anomalyType: $anomalyType,
description: $detection->message,
metrics: array_filter($metrics),
severity: $this->mapSeverityToString($detection->severity)
);
}
/**
* Create generic Input Validation OWASP event from WAF detection
*/
private function createGenericInputValidationEvent(Detection $detection, RequestContext $requestContext): InputValidationFailureEvent
{
$field = $detection->location ?? 'unknown_field';
$reason = $detection->category->getDescription();
return new InputValidationFailureEvent(
field: $field,
reason: $reason,
attemptedValue: $detection->payload?->getSample() ?? '',
email: $requestContext->getUserEmail()
);
}
/**
* Map WAF Detection Category to Input Type
*/
private function mapDetectionCategoryToInputType(DetectionCategory $category): string
{
return match ($category) {
DetectionCategory::COMMAND_INJECTION => 'command_injection',
DetectionCategory::LDAP_INJECTION => 'ldap_injection',
DetectionCategory::XPATH_INJECTION => 'xpath_injection',
DetectionCategory::NOSQL_INJECTION => 'nosql_injection',
DetectionCategory::XXE => 'xml_external_entity',
DetectionCategory::PATH_TRAVERSAL => 'path_traversal',
DetectionCategory::DESERIALIZATION => 'unsafe_deserialization',
default => 'generic_injection'
};
}
/**
* Map WAF Detection Category to Attack Type
*/
private function mapDetectionCategoryToAttackType(DetectionCategory $category): string
{
return match ($category) {
DetectionCategory::BRUTE_FORCE => 'brute_force',
DetectionCategory::CREDENTIAL_STUFFING => 'credential_stuffing',
DetectionCategory::AUTHENTICATION_BYPASS => 'authentication_bypass',
DetectionCategory::SESSION_FIXATION => 'session_fixation',
DetectionCategory::SESSION_HIJACKING => 'session_hijacking',
default => 'authentication_attack'
};
}
/**
* Map WAF Detection Category to Activity Type
*/
private function mapDetectionCategoryToActivityType(DetectionCategory $category): string
{
return match ($category) {
DetectionCategory::SUSPICIOUS_IP => 'suspicious_ip_activity',
DetectionCategory::MALICIOUS_BOT => 'malicious_bot_activity',
DetectionCategory::DOS_ATTACK => 'denial_of_service',
DetectionCategory::DDOS_ATTACK => 'distributed_denial_of_service',
DetectionCategory::SCRAPING_BOT => 'web_scraping',
DetectionCategory::SPAM_BOT => 'spam_activity',
DetectionCategory::AUTOMATED_ATTACK => 'automated_attack',
DetectionCategory::TOR_EXIT_NODE => 'tor_network_activity',
DetectionCategory::PROXY_DETECTION => 'proxy_usage',
default => 'suspicious_network_activity'
};
}
/**
* Map WAF Detection Category to Anomaly Type
*/
private function mapDetectionCategoryToAnomalyType(DetectionCategory $category): string
{
return match ($category) {
DetectionCategory::RATE_LIMIT_VIOLATION => 'rate_limit_anomaly',
DetectionCategory::ANOMALOUS_BEHAVIOR => 'behavioral_anomaly',
DetectionCategory::SUSPICIOUS_USER_AGENT => 'user_agent_anomaly',
DetectionCategory::FINGERPRINTING_ATTEMPT => 'fingerprinting_anomaly',
DetectionCategory::RECONNAISSANCE => 'reconnaissance_anomaly',
DetectionCategory::POLICY_VIOLATION => 'policy_violation_anomaly',
default => 'system_anomaly'
};
}
/**
* Map WAF Detection Severity to String
*/
private function mapSeverityToString(DetectionSeverity $severity): string
{
return match ($severity) {
DetectionSeverity::CRITICAL => 'critical',
DetectionSeverity::HIGH => 'high',
DetectionSeverity::MEDIUM => 'medium',
DetectionSeverity::LOW => 'low',
DetectionSeverity::INFO => 'info'
};
}
/**
* Create OWASP Event Identifier from WAF Detection
*/
public function createOWASPEventIdentifier(Detection $detection): OWASPEventIdentifier
{
return match ($detection->category) {
DetectionCategory::SQL_INJECTION => OWASPEventIdentifier::maliciousInput('sql_injection'),
DetectionCategory::XSS => OWASPEventIdentifier::maliciousInput('xss'),
DetectionCategory::COMMAND_INJECTION => OWASPEventIdentifier::maliciousInput('command_injection'),
DetectionCategory::AUTHENTICATION_BYPASS,
DetectionCategory::BRUTE_FORCE => OWASPEventIdentifier::authenticationFailure('anonymous'),
DetectionCategory::SESSION_HIJACKING => OWASPEventIdentifier::sessionHijacking('anonymous'),
DetectionCategory::PRIVILEGE_ESCALATION => OWASPEventIdentifier::privilegeEscalation('anonymous', 'user', 'admin'),
DetectionCategory::MALICIOUS_FILE_UPLOAD => OWASPEventIdentifier::fileUploadFailure('suspicious_file'),
DetectionCategory::DOS_ATTACK,
DetectionCategory::DDOS_ATTACK => OWASPEventIdentifier::systemAnomaly('denial_of_service'),
default => OWASPEventIdentifier::systemAnomaly($detection->category->value)
};
}
/**
* Map WAF Detection Severity to OWASP Log Level
*/
public function mapToOWASPLogLevel(Detection $detection): OWASPLogLevel
{
return match ($detection->severity) {
DetectionSeverity::CRITICAL => OWASPLogLevel::FATAL,
DetectionSeverity::HIGH => OWASPLogLevel::ERROR,
DetectionSeverity::MEDIUM => OWASPLogLevel::WARN,
DetectionSeverity::LOW => OWASPLogLevel::INFO,
DetectionSeverity::INFO => OWASPLogLevel::DEBUG
};
}
/**
* Determine XSS type from payload
*/
private function determineXssType(string $payload): string
{
$payload = strtolower($payload);
if (str_contains($payload, '<script') || str_contains($payload, 'javascript:')) {
return 'stored_xss';
} elseif (str_contains($payload, 'onload=') || str_contains($payload, 'onerror=') ||
str_contains($payload, 'onclick=') || str_contains($payload, 'onmouse')) {
return 'reflected_xss';
} elseif (str_contains($payload, 'document.') || str_contains($payload, 'window.')) {
return 'dom_xss';
}
return 'generic_xss';
}
}