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, ' 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, 'Startseite']; $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";