85 lines
4.8 KiB
PHP
85 lines
4.8 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Prüft die Sicherheitsprüfung (includes/security_check.php): erkennt sie erreichbare interne Dateien und ausführbare
|
|
* Uploads, und meldet sie nichts, wenn alles gesperrt ist? Der Webserver wird durch eine Abruf-Funktion simuliert.
|
|
*/
|
|
|
|
putenv('DESKHUB_SQLITE_PATH=:memory:');
|
|
require_once dirname(__DIR__) . '/includes/bootstrap.php';
|
|
|
|
$failures = [];
|
|
$check = function (bool $ok, string $what) use (&$failures): void {
|
|
if (!$ok) $failures[] = $what;
|
|
};
|
|
$levels = fn(array $rows) => array_column($rows, 'level');
|
|
|
|
// Gut konfigurierter Server: alles Interne 403, Unbekanntes 404
|
|
$secure = fn(string $url) => str_contains($url, 'deskhub-pruefung') ? [404, ''] : [403, ''];
|
|
$r = security_check_exposure('https://support.example.org', $secure);
|
|
$check($levels($r) === ['ok'], 'Gesperrter Server: nur "ok" erwartet, erhalten ' . implode(',', $levels($r)));
|
|
|
|
// Server ohne Sperrregeln (z. B. nginx ohne Konfiguration): Konfiguration und Datenbank liefern 200
|
|
$open = fn(string $url) => str_contains($url, 'deskhub-pruefung') ? [404, ''] : [200, '<?php return [];'];
|
|
$r = security_check_exposure('https://support.example.org', $open);
|
|
$check($levels($r) === ['error'], 'Offener Server muss einen Fehler melden');
|
|
$check(str_contains($r[0]['detail'], '/config/config.php') && str_contains($r[0]['detail'], '/database/deskhub.sqlite') && str_contains($r[0]['detail'], '/backups/'), 'Fehlertext nennt die erreichbaren Adressen: ' . $r[0]['detail']);
|
|
|
|
// Nur eine Adresse offen
|
|
$partial = fn(string $url) => str_contains($url, '/backups/') ? [200, 'Index of'] : (str_contains($url, 'deskhub-pruefung') ? [404, ''] : [403, '']);
|
|
$r = security_check_exposure('https://support.example.org/', $partial);
|
|
$check($levels($r) === ['error'] && str_contains($r[0]['detail'], '/backups/') && !str_contains($r[0]['detail'], 'config.php'), 'Genau die offene Adresse wird gemeldet');
|
|
|
|
// Server antwortet auf alles mit 200 (Catch-all): nicht aussagekräftig statt falschem Alarm
|
|
$catchAll = fn(string $url) => [200, '<html>Startseite</html>'];
|
|
$r = security_check_exposure('https://support.example.org', $catchAll);
|
|
$check($levels($r) === ['info'], 'Catch-all-Server: nur Hinweis "nicht prüfbar"');
|
|
|
|
// Nicht erreichbar
|
|
$down = fn(string $url) => [0, ''];
|
|
$r = security_check_exposure('https://support.example.org', $down);
|
|
$check($levels($r) === ['info'], 'Nicht erreichbar: nur Hinweis');
|
|
|
|
// Upload-Ausführung: simulierter Server führt die Datei aus (liefert den Marker) bzw. nicht
|
|
$dir = sys_get_temp_dir() . '/deskhub_sc_' . bin2hex(random_bytes(4));
|
|
mkdir($dir);
|
|
$executing = function (string $url) use ($dir): array {
|
|
$f = $dir . '/' . basename($url);
|
|
if (!is_file($f)) return [404, ''];
|
|
preg_match('/echo "([a-f0-9]+)"/', (string) file_get_contents($f), $m);
|
|
return [200, $m[1] ?? ''];
|
|
};
|
|
$notExecuting = function (string $url) use ($dir): array {
|
|
$f = $dir . '/' . basename($url);
|
|
return is_file($f) ? [200, (string) file_get_contents($f)] : [404, '']; // liefert den Quelltext aus, führt ihn nicht aus
|
|
};
|
|
$denied = fn(string $url) => [403, ''];
|
|
$r = security_check_upload_execution('https://support.example.org', $dir, $executing);
|
|
$check($r['level'] === 'error', 'Ausführbare Uploads müssen als Fehler gemeldet werden');
|
|
$r = security_check_upload_execution('https://support.example.org', $dir, $notExecuting);
|
|
$check($r['level'] === 'ok', 'Nicht ausgeführte Uploads: ok (Quelltext ist kein Marker)');
|
|
$r = security_check_upload_execution('https://support.example.org', $dir, $denied);
|
|
$check($r['level'] === 'ok', 'Gesperrte Uploads: ok');
|
|
$check(glob($dir . '/*') === [], 'Die Testdatei wird wieder gelöscht');
|
|
$r = security_check_upload_execution('https://support.example.org', $dir . '/gibt-es-nicht', $denied);
|
|
$check($r['level'] === 'info', 'Nicht beschreibbarer Ordner: Hinweis');
|
|
rmdir($dir);
|
|
|
|
// Einstellungsprüfungen laufen ohne Fehler und liefern Einträge mit gültigen Stufen
|
|
$pdo = get_db();
|
|
$rows = security_check_settings($pdo);
|
|
$check(count($rows) >= 3, 'Einstellungsprüfung liefert Ergebnisse');
|
|
foreach ($rows as $row) $check(in_array($row['level'], ['ok', 'warn', 'error', 'info'], true) && $row['title'] !== '', 'Gültiger Eintrag: ' . json_encode($row));
|
|
$all = security_check_all($pdo, false);
|
|
$check($all !== [] && $all[0]['level'] !== 'ok' || count(array_unique(array_column($all, 'level'))) === 1, 'Fehler stehen vor "ok" (Sortierung)');
|
|
$sorted = array_column($all, 'level');
|
|
$rank = ['error' => 0, 'warn' => 1, 'info' => 2, 'ok' => 3];
|
|
$check($sorted === array_values(array_map(fn($l) => $l, $sorted)) && array_map(fn($l) => $rank[$l], $sorted) === (function ($a) { sort($a); return $a; })(array_map(fn($l) => $rank[$l], $sorted)), 'Ergebnisse sind nach Dringlichkeit sortiert');
|
|
|
|
if ($failures) {
|
|
fwrite(STDERR, "FEHLER:\n- " . implode("\n- ", $failures) . "\n");
|
|
exit(1);
|
|
}
|
|
echo "Security check checks passed.\n";
|