Clean URLs and security improvements

- Add .htaccess rewrite rules for clean URLs (/nl/page, /admin/route)
- Add PHP dev server router with clean URL support
- Update admin template asset paths to absolute for clean URL compat
- All pentest fixes verified: CSRF on login, directory listing disabled,
  secure cookies, backup/sourcemap files removed, version disclosure off
This commit is contained in:
2026-07-14 15:28:53 +02:00
parent 98f74b2861
commit c244514a48
24 changed files with 233 additions and 205 deletions
+25 -25
View File
@@ -2,7 +2,7 @@
/**
* CodePress Admin Console - Entry Point
* Access via: /admin.php?route=login|dashboard|content|config|plugins|users|logout
* Access via: //admin/login|dashboard|content|config|plugins|users|logout
*/
// Security headers
@@ -29,7 +29,7 @@ if ($route === 'login') {
// All other routes require authentication
if (!$auth->isAuthenticated()) {
header('Location: admin.php?route=login');
header('Location: /admin/login');
exit;
}
@@ -37,7 +37,7 @@ if (!$auth->isAuthenticated()) {
switch ($route) {
case 'logout':
$auth->logout();
header('Location: admin.php?route=login');
header('Location: /admin/login');
exit;
case 'dashboard':
@@ -122,7 +122,7 @@ switch ($route) {
break;
default:
header('Location: admin.php?route=dashboard');
header('Location: /admin/dashboard');
exit;
}
@@ -143,7 +143,7 @@ function handleLogin(AdminAuth $auth): void
$result = $auth->login($username, $password);
if ($result['success']) {
$auth->regenerateCsrfToken();
header('Location: admin.php?route=dashboard');
header('Location: /admin/dashboard');
exit;
}
$error = $result['message'];
@@ -264,7 +264,7 @@ function handleContentEdit(AdminAuth $auth, array $config): void
$realPath = realpath($filePath);
$realContentDir = realpath($contentDir);
if (!$realPath || !$realContentDir || strpos($realPath, $realContentDir) !== 0) {
header('Location: admin.php?route=content');
header('Location: /admin/content');
exit;
}
@@ -405,7 +405,7 @@ function handleContentNew(AdminAuth $auth, array $config): void
}
file_put_contents($filePath, $content);
header('Location: admin.php?route=content&dir=' . urlencode($dir));
header('Location: /admin/content&dir=' . urlencode($dir));
exit;
}
}
@@ -454,14 +454,14 @@ function handleContentDelete(AdminAuth $auth, array $config): void
}
$dir = dirname($file);
header('Location: admin.php?route=content&dir=' . urlencode($dir === '.' ? '' : $dir));
header('Location: /admin/content&dir=' . urlencode($dir === '.' ? '' : $dir));
exit;
}
function handleContentDirCreate(AdminAuth $auth, array $config): void
{
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
header('Location: admin.php?route=content');
header('Location: /admin/content');
exit;
}
@@ -470,7 +470,7 @@ function handleContentDirCreate(AdminAuth $auth, array $config): void
$subdir = str_replace(['../', '..\\'], '', $subdir);
if (!$auth->verifyCsrf($_POST['csrf_token'] ?? '')) {
header('Location: admin.php?route=content&dir=' . urlencode($subdir));
header('Location: /admin/content&dir=' . urlencode($subdir));
exit;
}
@@ -483,7 +483,7 @@ function handleContentDirCreate(AdminAuth $auth, array $config): void
}
}
header('Location: admin.php?route=content&dir=' . urlencode($subdir));
header('Location: /admin/content&dir=' . urlencode($subdir));
exit;
}
@@ -498,7 +498,7 @@ function handleContentDirRename(AdminAuth $auth, array $config): void
$realContentDir = realpath($contentDir);
if (!$realPath || !$realContentDir || strpos($realPath, $realContentDir) !== 0 || !is_dir($fullPath)) {
header('Location: admin.php?route=content');
header('Location: /admin/content');
exit;
}
@@ -518,7 +518,7 @@ function handleContentDirRename(AdminAuth $auth, array $config): void
}
$parentRelative = dirname($dir);
header('Location: admin.php?route=content&dir=' . urlencode($parentRelative === '.' ? '' : $parentRelative));
header('Location: /admin/content&dir=' . urlencode($parentRelative === '.' ? '' : $parentRelative));
exit;
}
@@ -540,7 +540,7 @@ function handleContentMove(AdminAuth $auth, array $config): void
$realContentDir = realpath($contentDir);
if (!$realPath || !$realContentDir || strpos($realPath, $realContentDir) !== 0) {
header('Location: admin.php?route=content');
header('Location: /admin/content');
exit;
}
@@ -560,7 +560,7 @@ function handleContentMove(AdminAuth $auth, array $config): void
}
$parentRelative = is_file($fullPath) ? dirname($item) : dirname($item);
header('Location: admin.php?route=content&dir=' . urlencode($parentRelative === '.' ? '' : $parentRelative));
header('Location: /admin/content&dir=' . urlencode($parentRelative === '.' ? '' : $parentRelative));
exit;
}
@@ -598,7 +598,7 @@ function handleContentDirDelete(AdminAuth $auth, array $config): void
}
$parentDir = dirname($dir);
header('Location: admin.php?route=content&dir=' . urlencode($parentDir === '.' ? '' : $parentDir));
header('Location: /admin/content&dir=' . urlencode($parentDir === '.' ? '' : $parentDir));
exit;
}
@@ -833,7 +833,7 @@ function handlePluginConfig(AdminAuth $auth, array $config): void
$messageType = '';
if (empty($pluginName) || !is_dir($pluginPath)) {
header('Location: admin.php?route=plugins');
header('Location: /admin/plugins');
exit;
}
@@ -878,7 +878,7 @@ function handlePluginEdit(AdminAuth $auth, array $config): void
$messageType = '';
if (empty($pluginName) || !is_dir($pluginPath) || !file_exists($pluginFile)) {
header('Location: admin.php?route=plugins');
header('Location: /admin/plugins');
exit;
}
@@ -954,7 +954,7 @@ function handlePluginNew(AdminAuth $auth, array $config): void
file_put_contents($pluginPath . '/README.md', $readme);
}
header('Location: admin.php?route=plugins');
header('Location: /admin/plugins');
exit;
}
}
@@ -968,7 +968,7 @@ function handlePluginNew(AdminAuth $auth, array $config): void
function handlePluginToggle(AdminAuth $auth, array $config): void
{
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
header('Location: admin.php?route=plugins');
header('Location: /admin/plugins');
exit;
}
@@ -977,7 +977,7 @@ function handlePluginToggle(AdminAuth $auth, array $config): void
$pluginPath = $pluginsDir . '/' . $pluginName;
if (empty($pluginName) || !is_dir($pluginPath)) {
header('Location: admin.php?route=plugins');
header('Location: /admin/plugins');
exit;
}
@@ -992,14 +992,14 @@ function handlePluginToggle(AdminAuth $auth, array $config): void
}
}
header('Location: admin.php?route=plugins');
header('Location: /admin/plugins');
exit;
}
function handlePluginDelete(AdminAuth $auth, array $config): void
{
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
header('Location: admin.php?route=plugins');
header('Location: /admin/plugins');
exit;
}
@@ -1008,7 +1008,7 @@ function handlePluginDelete(AdminAuth $auth, array $config): void
$pluginPath = $pluginsDir . '/' . $pluginName;
if (empty($pluginName) || !is_dir($pluginPath)) {
header('Location: admin.php?route=plugins');
header('Location: /admin/plugins');
exit;
}
@@ -1021,7 +1021,7 @@ function handlePluginDelete(AdminAuth $auth, array $config): void
rmdir($pluginPath);
}
header('Location: admin.php?route=plugins');
header('Location: /admin/plugins');
exit;
}