generateSqlInjectionTestCases(); $blocked = 0; $failed = []; foreach ($testCases as $testCase) { $request = $this->createAttackRequest( uri: '/api/users', method: Method::GET, queryParams: ['id' => $testCase['payload']] ); $decision = $this->wafEngine->analyzeRequest($request); if ($decision->shouldBlock()) { $blocked++; } else { $failed[] = $testCase['description']; } } if (!empty($failed)) { throw new \RuntimeException( "WAF failed to block " . count($failed) . " SQL injection attacks:\n" . implode("\n", array_slice($failed, 0, 5)) ); } echo "✅ Blocked {$blocked}/" . count($testCases) . " SQL injection attacks in query params\n"; } /** * Test WAF blocks SQL injection in POST data */ public function testBlocksSqlInjectionInPostData(): void { $testCases = $this->generateSqlInjectionTestCases(); $blocked = 0; $failed = []; foreach ($testCases as $testCase) { $request = $this->createAttackRequest( uri: '/api/users', method: Method::POST, postData: [ 'username' => $testCase['payload'], 'email' => 'test@example.com' ] ); $decision = $this->wafEngine->analyzeRequest($request); if ($decision->shouldBlock()) { $blocked++; } else { $failed[] = $testCase['description']; } } if (!empty($failed)) { throw new \RuntimeException( "WAF failed to block " . count($failed) . " SQL injection attacks in POST data:\n" . implode("\n", array_slice($failed, 0, 5)) ); } echo "✅ Blocked {$blocked}/" . count($testCases) . " SQL injection attacks in POST data\n"; } /** * Test WAF blocks SQL injection in headers */ public function testBlocksSqlInjectionInHeaders(): void { $attacks = [ "' OR '1'='1", "'; DROP TABLE users--", "' UNION SELECT NULL--" ]; $blocked = 0; $failed = []; foreach ($attacks as $attack) { $request = $this->createAttackRequest( uri: '/api/users', method: Method::GET, headers: [ 'X-Custom-Header' => $attack, 'User-Agent' => 'Mozilla/5.0' ] ); $decision = $this->wafEngine->analyzeRequest($request); if ($decision->shouldBlock()) { $blocked++; } else { $failed[] = "Header injection: {$attack}"; } } if (!empty($failed)) { throw new \RuntimeException( "WAF failed to block SQL injection in headers:\n" . implode("\n", $failed) ); } echo "✅ Blocked {$blocked}/" . count($attacks) . " SQL injection attacks in headers\n"; } /** * Test WAF allows legitimate SQL-like strings */ public function testAllowsLegitimateStrings(): void { $legitimateStrings = [ "O'Reilly", // Apostrophe in name "user@example.com", // Email "What's up?", // Casual text with apostrophe "Price: $10-20", // Price range "SELECT * FROM table", // Code snippet in documentation field ]; $allowedCount = 0; $falsePositives = []; foreach ($legitimateStrings as $string) { $request = $this->createLegitimateRequest( uri: '/api/users', method: Method::POST, data: ['bio' => $string] ); $decision = $this->wafEngine->analyzeRequest($request); if (!$decision->shouldBlock()) { $allowedCount++; } else { $falsePositives[] = $string; } } if (!empty($falsePositives)) { echo "⚠️ Warning: WAF has " . count($falsePositives) . " false positives:\n"; foreach ($falsePositives as $fp) { echo " - {$fp}\n"; } } else { echo "✅ No false positives detected ({$allowedCount}/" . count($legitimateStrings) . " legitimate strings allowed)\n"; } } /** * Test WAF detects encoded SQL injection attempts */ public function testBlocksEncodedSqlInjection(): void { $encodedAttacks = [ urlencode("' OR '1'='1"), urlencode("'; DROP TABLE users--"), rawurlencode("' UNION SELECT NULL--"), ]; $blocked = 0; foreach ($encodedAttacks as $attack) { $request = $this->createAttackRequest( uri: '/api/users', method: Method::GET, queryParams: ['search' => $attack] ); $decision = $this->wafEngine->analyzeRequest($request); if ($decision->shouldBlock()) { $blocked++; } } echo "✅ Blocked {$blocked}/" . count($encodedAttacks) . " encoded SQL injection attacks\n"; } /** * Run all SQL injection tests */ public function runAllTests(): array { $results = []; try { $this->testBlocksSqlInjectionInQueryParams(); $results['query_params'] = 'PASS'; } catch (\Exception $e) { $results['query_params'] = 'FAIL: ' . $e->getMessage(); } try { $this->testBlocksSqlInjectionInPostData(); $results['post_data'] = 'PASS'; } catch (\Exception $e) { $results['post_data'] = 'FAIL: ' . $e->getMessage(); } try { $this->testBlocksSqlInjectionInHeaders(); $results['headers'] = 'PASS'; } catch (\Exception $e) { $results['headers'] = 'FAIL: ' . $e->getMessage(); } try { $this->testAllowsLegitimateStrings(); $results['false_positives'] = 'PASS'; } catch (\Exception $e) { $results['false_positives'] = 'FAIL: ' . $e->getMessage(); } try { $this->testBlocksEncodedSqlInjection(); $results['encoded_attacks'] = 'PASS'; } catch (\Exception $e) { $results['encoded_attacks'] = 'FAIL: ' . $e->getMessage(); } return $results; } }