- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
282 lines
9.0 KiB
PHP
282 lines
9.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Framework\DDoS\Components\AttackPatternDetector;
|
|
use App\Framework\DDoS\DDoSConfig;
|
|
use App\Framework\DDoS\ValueObjects\AttackPattern;
|
|
use App\Framework\Logging\DefaultLogger;
|
|
use App\Framework\Logging\LogLevel;
|
|
|
|
require_once __DIR__ . '/../Helpers/TestHelpers.php';
|
|
|
|
beforeEach(function () {
|
|
// Create development config (more permissive for testing)
|
|
$config = DDoSConfig::development();
|
|
|
|
// Create logger
|
|
$logger = new DefaultLogger(LogLevel::DEBUG);
|
|
|
|
$this->detector = new AttackPatternDetector($config, $logger);
|
|
});
|
|
|
|
describe('AttackPatternDetector', function () {
|
|
|
|
it('detects volumetric attacks', function () {
|
|
$analysisResults = [
|
|
'traffic_patterns' => [
|
|
'threat_score' => 0.9, // Higher than development config threshold (0.8)
|
|
'requests_per_minute' => 500,
|
|
'normal_rate' => 50,
|
|
],
|
|
];
|
|
|
|
$request = createTestRequest('192.168.1.100', 'GET', '/api/data');
|
|
|
|
$patterns = $this->detector->identifyAttackPatterns($analysisResults, $request);
|
|
|
|
expect($patterns)->toContain(AttackPattern::VOLUMETRIC);
|
|
});
|
|
|
|
it('detects distributed attacks', function () {
|
|
$analysisResults = [
|
|
'geo_anomalies' => [
|
|
'threat_score' => 0.7,
|
|
'unique_countries' => 15,
|
|
'geographic_diversity' => 0.9,
|
|
],
|
|
];
|
|
|
|
$request = createTestRequest('10.0.0.1', 'POST', '/api/login');
|
|
|
|
$patterns = $this->detector->identifyAttackPatterns($analysisResults, $request);
|
|
|
|
expect($patterns)->toContain(AttackPattern::DISTRIBUTED);
|
|
});
|
|
|
|
it('detects bot attacks from user agent patterns', function () {
|
|
$analysisResults = [
|
|
'request_signature' => [
|
|
'threat_score' => 0.6,
|
|
'user_agent_suspicion' => 0.8,
|
|
'automation_indicators' => ['unusual_timing', 'fixed_intervals'],
|
|
],
|
|
];
|
|
|
|
$request = createTestRequest('192.168.1.200', 'GET', '/scrape-data', [
|
|
'User-Agent' => 'ScrapingBot/2.0 (automated)',
|
|
]);
|
|
|
|
$patterns = $this->detector->identifyAttackPatterns($analysisResults, $request);
|
|
|
|
expect($patterns)->toContain(AttackPattern::BOTNET);
|
|
});
|
|
|
|
it('detects application layer attacks', function () {
|
|
$analysisResults = [
|
|
'waf_analysis' => [
|
|
'threat_score' => 0.9,
|
|
'malicious_patterns' => ['sql_injection', 'xss_attempt'],
|
|
'payload_analysis' => 'high_risk',
|
|
],
|
|
];
|
|
|
|
$request = createTestRequest('192.168.1.300', 'POST', '/api/search', [], [
|
|
'query' => "'; DROP TABLE users; --",
|
|
]);
|
|
|
|
$patterns = $this->detector->identifyAttackPatterns($analysisResults, $request);
|
|
|
|
expect($patterns)->toContain(AttackPattern::APPLICATION_LAYER);
|
|
});
|
|
|
|
it('detects slow rate attacks', function () {
|
|
$analysisResults = [
|
|
'traffic_patterns' => [
|
|
'threat_score' => 0.4,
|
|
'requests_per_minute' => 30,
|
|
'sustained_duration' => 3600, // 1 hour
|
|
'pattern_consistency' => 0.95,
|
|
],
|
|
];
|
|
|
|
$request = createTestRequest('192.168.1.400', 'GET', '/expensive-operation');
|
|
|
|
$patterns = $this->detector->identifyAttackPatterns($analysisResults, $request);
|
|
|
|
expect($patterns)->toContain(AttackPattern::SLOWLORIS);
|
|
});
|
|
|
|
it('detects mixed attack patterns', function () {
|
|
$analysisResults = [
|
|
'traffic_patterns' => [
|
|
'threat_score' => 0.8,
|
|
'requests_per_minute' => 300,
|
|
],
|
|
'geo_anomalies' => [
|
|
'threat_score' => 0.6,
|
|
'unique_countries' => 10,
|
|
],
|
|
'waf_analysis' => [
|
|
'threat_score' => 0.7,
|
|
'malicious_patterns' => ['xss_attempt'],
|
|
],
|
|
];
|
|
|
|
$request = createTestRequest('192.168.1.500', 'POST', '/api/submit');
|
|
|
|
$patterns = $this->detector->identifyAttackPatterns($analysisResults, $request);
|
|
|
|
expect($patterns)->toHaveCount(3);
|
|
expect($patterns)->toContain(AttackPattern::VOLUMETRIC);
|
|
expect($patterns)->toContain(AttackPattern::DISTRIBUTED);
|
|
expect($patterns)->toContain(AttackPattern::APPLICATION_LAYER);
|
|
});
|
|
|
|
it('returns empty array for normal traffic', function () {
|
|
$analysisResults = [
|
|
'traffic_patterns' => [
|
|
'threat_score' => 0.1,
|
|
'requests_per_minute' => 15,
|
|
],
|
|
'geo_anomalies' => [
|
|
'threat_score' => 0.05,
|
|
'unique_countries' => 1,
|
|
],
|
|
];
|
|
|
|
$request = createTestRequest('192.168.1.600', 'GET', '/api/health');
|
|
|
|
$patterns = $this->detector->identifyAttackPatterns($analysisResults, $request);
|
|
|
|
expect($patterns)->toBeEmpty();
|
|
});
|
|
|
|
it('identifies coordinated attack patterns', function () {
|
|
$analysisResults = [
|
|
'traffic_patterns' => [
|
|
'threat_score' => 0.6,
|
|
'coordination_score' => 0.8,
|
|
'timing_patterns' => 'synchronized',
|
|
],
|
|
];
|
|
|
|
$request = createTestRequest('192.168.1.700', 'GET', '/target-endpoint');
|
|
|
|
$patterns = $this->detector->identifyAttackPatterns($analysisResults, $request);
|
|
|
|
expect($patterns)->toContain(AttackPattern::DISTRIBUTED);
|
|
});
|
|
|
|
it('detects amplification attacks', function () {
|
|
$analysisResults = [
|
|
'traffic_patterns' => [
|
|
'threat_score' => 0.7,
|
|
'amplification_ratio' => 50,
|
|
'response_size_anomaly' => 0.9,
|
|
],
|
|
];
|
|
|
|
$request = createTestRequest('192.168.1.800', 'GET', '/api/export-large-dataset');
|
|
|
|
$patterns = $this->detector->identifyAttackPatterns($analysisResults, $request);
|
|
|
|
expect($patterns)->toContain(AttackPattern::AMPLIFICATION);
|
|
});
|
|
|
|
it('handles malformed analysis results', function () {
|
|
$analysisResults = [
|
|
'invalid_layer' => null,
|
|
'broken_data' => 'not_an_array',
|
|
];
|
|
|
|
$request = createTestRequest('192.168.1.900', 'GET', '/api/test');
|
|
|
|
$patterns = $this->detector->identifyAttackPatterns($analysisResults, $request);
|
|
|
|
expect($patterns)->toBeArray();
|
|
});
|
|
|
|
it('calculates pattern confidence scores', function () {
|
|
$analysisResults = [
|
|
'traffic_patterns' => [
|
|
'threat_score' => 0.8,
|
|
'confidence' => 0.9,
|
|
],
|
|
];
|
|
|
|
$request = createTestRequest('192.168.1.100', 'GET', '/api/data');
|
|
|
|
$confidence = $this->detector->calculatePatternConfidence($analysisResults);
|
|
|
|
expect($confidence)->toBeBetween(0.0, 1.0);
|
|
expect($confidence)->toBeGreaterThan(0.7);
|
|
});
|
|
|
|
it('provides pattern severity assessment', function () {
|
|
$patterns = [
|
|
AttackPattern::VOLUMETRIC,
|
|
AttackPattern::APPLICATION_LAYER,
|
|
];
|
|
|
|
$severity = $this->detector->assessPatternSeverity($patterns);
|
|
|
|
expect($severity)->toBeIn(['low', 'medium', 'high', 'critical']);
|
|
});
|
|
|
|
});
|
|
|
|
describe('Pattern Analysis Details', function () {
|
|
|
|
it('provides detailed pattern analysis', function () {
|
|
$analysisResults = [
|
|
'traffic_patterns' => [
|
|
'threat_score' => 0.8,
|
|
'requests_per_minute' => 500,
|
|
'peak_detection' => true,
|
|
],
|
|
];
|
|
|
|
$request = createTestRequest('192.168.1.100', 'GET', '/api/data');
|
|
|
|
$details = $this->detector->getPatternAnalysisDetails($analysisResults, $request);
|
|
|
|
expect($details)->toHaveKeys([
|
|
'detected_patterns',
|
|
'confidence_scores',
|
|
'risk_factors',
|
|
'recommendations',
|
|
]);
|
|
});
|
|
|
|
it('tracks pattern evolution over time', function () {
|
|
$historicalData = [
|
|
['timestamp' => time() - 3600, 'patterns' => [AttackPattern::VOLUMETRIC]],
|
|
['timestamp' => time() - 1800, 'patterns' => [AttackPattern::VOLUMETRIC, AttackPattern::BOTNET]],
|
|
['timestamp' => time(), 'patterns' => [AttackPattern::DISTRIBUTED]],
|
|
];
|
|
|
|
$evolution = $this->detector->analyzePatternEvolution($historicalData);
|
|
|
|
expect($evolution)->toHaveKeys(['trend', 'escalation_detected', 'pattern_changes']);
|
|
expect($evolution['escalation_detected'])->toBeTrue();
|
|
});
|
|
|
|
it('generates pattern fingerprints', function () {
|
|
$analysisResults = [
|
|
'traffic_patterns' => ['threat_score' => 0.8],
|
|
'geo_anomalies' => ['threat_score' => 0.6],
|
|
];
|
|
|
|
$request = createTestRequest('192.168.1.100', 'GET', '/api/data');
|
|
|
|
$fingerprint = $this->detector->generatePatternFingerprint($analysisResults, $request);
|
|
|
|
expect($fingerprint)->toBeString();
|
|
expect(strlen($fingerprint))->toBeGreaterThan(10);
|
|
});
|
|
|
|
});
|
|
|
|
// Helper functions are now in ../Helpers/TestHelpers.php
|