Security: verwijder hardcoded wachtwoord, voeg random-wachtwoord-generator toe bij eerste installatie
This commit is contained in:
+102
-7
@@ -1,12 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Front-end entry point van CodePress CMS.
|
||||
*
|
||||
* Bootstrap de CMS-core, laadt de configuratie, stuurt security headers uit,
|
||||
* serveert media-/asset-/robots-requests, voert BotGuard- en rate-limit-
|
||||
* controles uit, registreert analytics- en logvermeldingen en render
|
||||
* uiteindelijk de pagina via CodePressCMS::render().
|
||||
*
|
||||
* @since 2.6.4
|
||||
* @package CodePress
|
||||
*/
|
||||
require_once __DIR__ . '/../cms/core/index.php';
|
||||
|
||||
$config = include __DIR__ . '/../cms/core/config.php';
|
||||
|
||||
/**
|
||||
* Log-systeem initialiseren op basis van de logging-configuratie.
|
||||
*
|
||||
* @since 2.6.4
|
||||
*/
|
||||
// Initialize dynamic logging
|
||||
LogManager::init($config['logging'] ?? []);
|
||||
|
||||
/**
|
||||
* Security headers instellen voor alle front-end responses.
|
||||
*
|
||||
* @since 2.6.4
|
||||
*/
|
||||
// Security headers
|
||||
header('X-Content-Type-Options: nosniff');
|
||||
header('X-Frame-Options: SAMEORIGIN');
|
||||
@@ -15,6 +36,15 @@ header('Referrer-Policy: strict-origin-when-cross-origin');
|
||||
header('Content-Security-Policy: default-src \'self\'; script-src \'self\' \'unsafe-inline\'; style-src \'self\' \'unsafe-inline\'; img-src \'self\' data:; font-src \'self\';');
|
||||
header_remove('X-Powered-By');
|
||||
|
||||
/**
|
||||
* Media- en asset-serving via /-media/ en /-assets/ routes.
|
||||
*
|
||||
* Bepaalt het verzoekpad en de toegestane MIME-types, resolveert de
|
||||
* content-map dynamisch op basis van config['content_dir'] en serveert
|
||||
* bestanden buiten public/ met een pad-controle om traversal te blokkeren.
|
||||
*
|
||||
* @since 2.6.4
|
||||
*/
|
||||
// Serve media files from any content/ subdirectory via /-media/
|
||||
// Serve files from content/-assets/ via /-assets/ (backward compatible)
|
||||
$requestUri = $_SERVER['REQUEST_URI'] ?? '';
|
||||
@@ -31,11 +61,15 @@ $mimeTypes = [
|
||||
'css' => 'text/css', 'js' => 'application/javascript',
|
||||
];
|
||||
|
||||
// Resolve the content directory once (absolute, from config) so media
|
||||
// serving follows a customised content_dir instead of a hardcoded path.
|
||||
$contentBase = realpath($config['content_dir']);
|
||||
$contentBase = $contentBase !== false ? $contentBase : rtrim($config['content_dir'], '/');
|
||||
|
||||
if (strpos($path, '/-media/') === 0) {
|
||||
$relative = ltrim(substr($path, 7), '/');
|
||||
$root = realpath(__DIR__ . '/..');
|
||||
$filePath = $root . '/content/' . $relative;
|
||||
if (strpos($filePath, $root . '/content') === 0) {
|
||||
$filePath = $contentBase . '/' . $relative;
|
||||
if ($contentBase !== '' && strpos($filePath, $contentBase) === 0) {
|
||||
$ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
|
||||
if (in_array($ext, $allowedExt) && file_exists($filePath) && !is_dir($filePath)) {
|
||||
if (isset($mimeTypes[$ext])) {
|
||||
@@ -50,18 +84,23 @@ if (strpos($path, '/-media/') === 0) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* /-assets/ route: serveert bestanden uit content/-assets/ of de content-
|
||||
* root, met backward-compatibiliteit en path-traversal-controle.
|
||||
*
|
||||
* @since 2.6.4
|
||||
*/
|
||||
if (strpos($path, '/-assets/') === 0) {
|
||||
$relative = ltrim(substr($path, 8), '/');
|
||||
$root = realpath(__DIR__ . '/..');
|
||||
|
||||
$servePath = null;
|
||||
$candidates = [
|
||||
$root . '/content/-assets/' . $relative,
|
||||
$root . '/content/' . $relative,
|
||||
$contentBase . '/-assets/' . $relative,
|
||||
$contentBase . '/' . $relative,
|
||||
];
|
||||
|
||||
foreach ($candidates as $candidate) {
|
||||
if (strpos($candidate, $root . '/content') !== 0) continue;
|
||||
if ($contentBase === '' || strpos($candidate, $contentBase) !== 0) continue;
|
||||
if (file_exists($candidate) && !is_dir($candidate)) {
|
||||
$ext = strtolower(pathinfo($candidate, PATHINFO_EXTENSION));
|
||||
if (in_array($ext, $allowedExt)) {
|
||||
@@ -92,6 +131,13 @@ if ($path === '/robots.txt') {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Directe toegang tot /content/ blokkeren.
|
||||
*
|
||||
* Voorkomt dat ruwe content-bestanden via het web opgevraagd worden.
|
||||
*
|
||||
* @since 2.6.4
|
||||
*/
|
||||
// Block direct access to content files
|
||||
if (strpos($path, '/content/') === 0) {
|
||||
http_response_code(403);
|
||||
@@ -99,6 +145,16 @@ if (strpos($path, '/content/') === 0) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Security-checks en rate limiting uitvoeren.
|
||||
*
|
||||
* Bepaalt client-IP, BotGuard-controle, IP-blocklist en rate-limiter op
|
||||
* basis van de security-config. IP's op de allowed/uitgesloten lijsten
|
||||
* slaan de controles over. Het requestStatus wordt bijgehouden voor
|
||||
* latere logging en blocking.
|
||||
*
|
||||
* @since 2.6.4
|
||||
*/
|
||||
// Load RequestLogger for IP & request logging
|
||||
require_once __DIR__ . '/../cms/core/class/RequestLogger.php';
|
||||
|
||||
@@ -149,9 +205,22 @@ if (!$isAllowedIp) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CMS-instantie aanmaken met de geladen configuratie.
|
||||
*
|
||||
* @since 2.6.4
|
||||
*/
|
||||
// Instantiate CMS instance
|
||||
$cms = new CodePressCMS($config);
|
||||
|
||||
/**
|
||||
* Analytics en GeoIP-lookup uitvoeren.
|
||||
*
|
||||
* Land, IP-anonimisatie en analytics-instellingen worden bepaald op basis
|
||||
* van de analytics-configuratie.
|
||||
*
|
||||
* @since 2.6.4
|
||||
*/
|
||||
// Analytics & GeoIP settings
|
||||
$analyticsSettings = $config['analytics'] ?? [];
|
||||
$geoCountry = null;
|
||||
@@ -160,11 +229,25 @@ if (!empty($analyticsSettings['enabled'])) {
|
||||
$geoCountry = $geoIp->lookupCountry($clientIp);
|
||||
}
|
||||
|
||||
/**
|
||||
* IP-anonimisatie toepassen voor opslag indien ingeschakeld.
|
||||
*
|
||||
* @since 2.6.4
|
||||
*/
|
||||
// Apply IP anonymization for storage if enabled
|
||||
$storedIp = !empty($analyticsSettings['anonymize_ip'])
|
||||
? RequestLogger::anonymizeIp($clientIp)
|
||||
: $clientIp;
|
||||
|
||||
/**
|
||||
* Pagina-view loggen (niet voor media-/assets-requests).
|
||||
*
|
||||
* Start sessie indien nodig, stelt huidige pagina/referrer vast, schrijft
|
||||
* een request-logregel, vuurt een LogManager-requestevent en registreert
|
||||
* geaggregeerde analytics (mits ingeschakeld en IP niet uitgesloten).
|
||||
*
|
||||
* @since 2.6.4
|
||||
*/
|
||||
// Log page view (not for media/assets)
|
||||
if (!str_starts_with($path, '/-media/') && !str_starts_with($path, '/-assets/')) {
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
@@ -203,6 +286,13 @@ if (!str_starts_with($path, '/-media/') && !str_starts_with($path, '/-assets/'))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Geblokkeerde verzoeken afhandelen.
|
||||
*
|
||||
* Geeft 429 bij rate-limit en 403 bij andere blokkades, met noindex-headers.
|
||||
*
|
||||
* @since 2.6.4
|
||||
*/
|
||||
// Block request if status is not ok
|
||||
if ($requestStatus !== 'ok') {
|
||||
if ($requestStatus === 'blocked:ratelimit') {
|
||||
@@ -216,4 +306,9 @@ if ($requestStatus !== 'ok') {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pagina renderen via de CodePressCMS-instantie.
|
||||
*
|
||||
* @since 2.6.4
|
||||
*/
|
||||
$cms->render();
|
||||
Reference in New Issue
Block a user