- Implemented SecurityTest to validate token generation, CSRF protection, input sanitization, and rate limiting. - Created UserModelTest to ensure correct database operations for user management, including creation, updating, banning, and fetching active users. - Developed ValidationTest to verify input validation and sanitization for user IDs, nicknames, messages, and API requests. - Introduced Security and Validation utility classes with methods for secure token generation, input sanitization, and comprehensive validation rules.
148 lines
4.8 KiB
PHP
148 lines
4.8 KiB
PHP
<?php
|
|
/**
|
|
* Application Bootstrap
|
|
* Initializes core components and security settings
|
|
*/
|
|
|
|
// Start sessions securely
|
|
if (session_status() === PHP_SESSION_NONE) {
|
|
// Secure session configuration
|
|
ini_set('session.use_strict_mode', 1);
|
|
ini_set('session.cookie_httponly', 1);
|
|
ini_set('session.cookie_secure', Config::get('session.secure', false));
|
|
ini_set('session.cookie_samesite', Config::get('session.samesite', 'Strict'));
|
|
ini_set('session.gc_maxlifetime', Config::get('session.lifetime', 7200));
|
|
|
|
session_start();
|
|
}
|
|
|
|
// Load autoloader first for PSR-4 class loading
|
|
require_once __DIR__ . '/includes/autoloader.php';
|
|
|
|
// Initialize configuration
|
|
try {
|
|
Config::load();
|
|
} catch (Exception $e) {
|
|
error_log("Configuration load failed: " . $e->getMessage());
|
|
http_response_code(500);
|
|
die("Configuration error. Please check server logs.");
|
|
}
|
|
|
|
// Initialize error handling with proper environment detection
|
|
ErrorHandler::initialize();
|
|
|
|
// Set PHP configuration based on environment
|
|
if (Config::isEnvironment('production')) {
|
|
ini_set('display_errors', 0);
|
|
ini_set('log_errors', 1);
|
|
error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);
|
|
error_log("Application running in PRODUCTION mode");
|
|
} elseif (Config::isEnvironment('staging')) {
|
|
ini_set('display_errors', 0);
|
|
ini_set('log_errors', 1);
|
|
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
|
|
error_log("Application running in STAGING mode");
|
|
} else { // development
|
|
ini_set('display_errors', 1);
|
|
ini_set('log_errors', 1);
|
|
error_reporting(E_ALL);
|
|
error_log("Application running in DEVELOPMENT mode");
|
|
}
|
|
|
|
// Basic security headers
|
|
function setSecurityHeaders() {
|
|
// Prevent clickjacking
|
|
header('X-Frame-Options: DENY');
|
|
|
|
// Prevent MIME sniffing
|
|
header('X-Content-Type-Options: nosniff');
|
|
|
|
// Referrer policy
|
|
header('Referrer-Policy: strict-origin-when-cross-origin');
|
|
|
|
// CSP headers (basic)
|
|
$csp = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self'";
|
|
header("Content-Security-Policy: $csp");
|
|
|
|
// HSTS (only in production with HTTPS)
|
|
if (Config::isEnvironment('production') && (!empty($_SERVER['HTTPS']) || $_SERVER['SERVER_PORT'] == 443)) {
|
|
header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
|
|
}
|
|
}
|
|
|
|
// Input sanitization for all GET/POST data
|
|
function sanitizeGlobalInputs() {
|
|
$_GET = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING) ?? [];
|
|
$_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING) ?? [];
|
|
}
|
|
|
|
// Rate limiting check
|
|
function checkGlobalRateLimit() {
|
|
$clientIP = Security::getClientIP();
|
|
$isLimited = !Security::checkRateLimit($clientIP, 'global');
|
|
|
|
if ($isLimited) {
|
|
Security::logSecurityEvent('rate_limit_exceeded', ['ip' => $clientIP]);
|
|
http_response_code(429);
|
|
die(json_encode(['error' => 'Too many requests. Please try again later.']));
|
|
}
|
|
}
|
|
|
|
// Initialize CSRF token if not exists
|
|
if (!isset($_SESSION['csrf_token'])) {
|
|
Security::generateCSRFToken();
|
|
}
|
|
|
|
// Generate or validate user ID
|
|
if (!isset($_SESSION['user_id'])) {
|
|
$_SESSION['user_id'] = Security::generateSecureUserId();
|
|
} elseif (!Validation::validateUserId($_SESSION['user_id'])['valid']) {
|
|
// Regenerate invalid user ID
|
|
$_SESSION['user_id'] = Security::generateSecureUserId();
|
|
}
|
|
|
|
// Check for admin authentication state
|
|
$isAdmin = Security::isAdminAuthenticated();
|
|
|
|
// Handle admin logout
|
|
if (isset($_GET['logout']) && $isAdmin) {
|
|
Security::logoutAdmin();
|
|
Security::logSecurityEvent('admin_logout');
|
|
header('Location: ' . $_SERVER['PHP_SELF']);
|
|
exit;
|
|
}
|
|
|
|
// Security checks for sensitive operations
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
// Validate CSRF token for POST requests
|
|
if (!Security::validateCSRFToken()) {
|
|
Security::logSecurityEvent('csrf_token_invalid');
|
|
http_response_code(403);
|
|
die(json_encode(['error' => 'Invalid security token']));
|
|
}
|
|
|
|
// Detect suspicious activity
|
|
$warnings = Security::detectSuspiciousActivity();
|
|
if (!empty($warnings)) {
|
|
foreach ($warnings as $warning) {
|
|
Security::logSecurityEvent('suspicious_activity_detected', ['warning' => $warning]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Apply rate limiting to API endpoints
|
|
if (strpos($_SERVER['REQUEST_URI'], '?api=') !== false ||
|
|
strpos($_SERVER['REQUEST_URI'], '?proxy=') !== false) {
|
|
checkGlobalRateLimit();
|
|
}
|
|
|
|
// Set security headers for all responses
|
|
setSecurityHeaders();
|
|
|
|
// Sanitize input data
|
|
sanitizeGlobalInputs();
|
|
|
|
// Log successful bootstrap
|
|
if (Config::isDebug()) {
|
|
error_log("Bootstrap completed for user: " . $_SESSION['user_id'] . ($isAdmin ? ' (admin)' : ''));
|
|
}
|