mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-07 03:29:19 +02:00
SecurityTest::Test1 was calling $db->searchTheses($string) with a plain string, but searchTheses() was refactored to require array $params when the tag M2M work landed. This caused an immediate PHP fatal TypeError before any SQL ever ran, killing the entire Security test suite with exit code 255 and masking all three tests. Fix: pass each malicious payload via ['query' => $string] which is the correct API and properly exercises the parameterised query path through validateSearchParams() + buildSearchConditions(). Added a clarifying comment explaining why the array form is required. All 4 test suites now pass: - Database (Unit): 7/7 - Rate Limit (Unit): 5/5 - Search (Integration): 6/6 - Security: 3/3
73 lines
2.4 KiB
PHP
73 lines
2.4 KiB
PHP
<?php
|
|
/**
|
|
* Security Test Suite
|
|
* Tests SQL injection protection and input sanitization
|
|
*/
|
|
|
|
require_once __DIR__ . '/../../src/Database.php';
|
|
|
|
echo "Security Test Suite\n";
|
|
echo "===================\n\n";
|
|
|
|
try {
|
|
$db = Database::getInstance();
|
|
|
|
// Test 1: SQL Injection in search
|
|
// searchTheses() takes an array of validated params; the 'query' key is the
|
|
// free-text search field that users control. Each malicious string must
|
|
// be passed as ['query' => $string] to exercise the actual parameterised
|
|
// query path rather than triggering a PHP TypeError before any SQL runs.
|
|
echo "Test 1: SQL Injection Protection (Search)\n";
|
|
$maliciousQueries = [
|
|
"' OR '1'='1",
|
|
"'; DROP TABLE theses; --",
|
|
"1' UNION SELECT * FROM authors--",
|
|
"<script>alert('xss')</script>",
|
|
];
|
|
|
|
foreach ($maliciousQueries as $query) {
|
|
try {
|
|
$results = $db->searchTheses(['query' => $query]);
|
|
// Should return a (possibly empty) result set without throwing
|
|
echo " ✓ Handled safely: " . substr($query, 0, 40) . "\n";
|
|
} catch (Exception $e) {
|
|
// A thrown exception is also acceptable (query rejected upstream)
|
|
echo " ✓ Exception (safe): " . substr($query, 0, 40) . "\n";
|
|
}
|
|
}
|
|
echo "✓ PASS: SQL injection attempts handled safely\n\n";
|
|
|
|
// Test 2: Invalid thesis ID
|
|
echo "Test 2: Invalid Thesis ID\n";
|
|
$invalidIds = ["abc", "'; DROP TABLE theses;", "-1", "999999"];
|
|
|
|
foreach ($invalidIds as $id) {
|
|
$result = $db->getThesisById($id);
|
|
if ($result === null || $result === false) {
|
|
echo " ✓ Rejected: " . $id . "\n";
|
|
} else {
|
|
throw new Exception("Invalid ID '$id' was not rejected");
|
|
}
|
|
}
|
|
echo "✓ PASS: Invalid IDs rejected\n\n";
|
|
|
|
// Test 3: XSS in output (checking data is escaped)
|
|
echo "Test 3: XSS Protection (Output Escaping)\n";
|
|
$theses = $db->getPublishedTheses(1, 0);
|
|
if (count($theses) > 0) {
|
|
$first = $theses[0];
|
|
// Check that HTML special chars would be handled
|
|
if (isset($first['title'])) {
|
|
echo " ✓ Title data retrieved safely\n";
|
|
}
|
|
}
|
|
echo "✓ PASS: Output handling verified\n\n";
|
|
|
|
echo "✅ All security tests passed!\n";
|
|
return true;
|
|
|
|
} catch (Exception $e) {
|
|
echo "❌ FAIL: " . $e->getMessage() . "\n";
|
|
return false;
|
|
}
|