Files
domnitor/core/SessionConfig.php
Hosteroid e3006738a9 Improve security, validation, and isolation checks
Add multiple security and validation improvements across the app:

- Prevent session fixation: regenerate session ID on login and after successful 2FA; tighten session cookie params (Secure, HttpOnly, SameSite=Lax).
- Harden installer: add CSRF checks for install/update flows and use PDO::quote when injecting admin credentials into SQL migration to avoid injection; add csrf_field() to installer templates.
- Template hardening: add safe_url and safe_mailto Twig filters, escape tag names for JS, and add rel="noopener noreferrer" to external links to mitigate XSS/opener risks.
- Domain controller: validate referrer to avoid open redirects, enforce user isolation mode when finding/deleting/updating domains and when assigning notification groups (ensures users only affect their own resources).
- Notification groups: verify channel belongs to group before deleting or toggling to prevent unauthorized access.
- ErrorLog: whitelist allowed sort columns to avoid arbitrary column injection in ORDER BY.
- Routes: move the debug whois route to protected/admin area.

These changes collectively reduce attack surface (XSS, open redirect, session fixation, SQL injection) and enforce proper resource isolation and input validation.
2026-03-11 00:03:54 +02:00

89 lines
2.7 KiB
PHP

<?php
namespace Core;
/**
* Session Configuration
*
* Handles session handler configuration and initialization
*/
class SessionConfig
{
/**
* Configure and initialize session handler
*
* Attempts to use database sessions if available, falls back to file sessions
*/
public static function configure(): void
{
try {
// Check if database sessions are available
if (self::isDatabaseSessionsAvailable()) {
$sessionLifetime = (int)($_ENV['SESSION_LIFETIME'] ?? 1440);
$handler = new DatabaseSessionHandler($sessionLifetime);
session_set_save_handler($handler, true);
}
// If not available, PHP will use default file-based sessions (no action needed)
} catch (\Exception $e) {
// Fall back to default file-based sessions
error_log("Database session handler not available, using file sessions: " . $e->getMessage());
}
}
/**
* Check if database sessions are available
*
* @return bool True if sessions table exists and database is accessible
*/
private static function isDatabaseSessionsAvailable(): bool
{
try {
// Check if database credentials are configured
if (empty($_ENV['DB_HOST']) || empty($_ENV['DB_DATABASE'])) {
return false;
}
// Create PDO connection
$pdo = new \PDO(
"mysql:host={$_ENV['DB_HOST']};dbname={$_ENV['DB_DATABASE']}",
$_ENV['DB_USERNAME'],
$_ENV['DB_PASSWORD'],
[
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC
]
);
// Check if sessions table exists
$stmt = $pdo->query("SHOW TABLES LIKE 'sessions'");
return $stmt->rowCount() > 0;
} catch (\Exception $e) {
// Database not available or sessions table doesn't exist
return false;
}
}
/**
* Start session with validation
*/
public static function start(): void
{
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'domain' => '',
'secure' => !empty($_SERVER['HTTPS']),
'httponly' => true,
'samesite' => 'Lax',
]);
session_start();
// Validate session exists in database (for database-backed sessions)
// This ensures deleted sessions are immediately invalidated
SessionValidator::validate();
}
}