appKey = getenv('APP_KEY') ?: 'default-key-change-in-production'; $this->csrfTokenName = getenv('CSRF_TOKEN_NAME') ?: '_token'; } /** * Initialize security features */ public function initialize(): void { // Set security headers $this->setSecurityHeaders(); // Sanitize input $this->sanitizeInput(); // Generate CSRF token if needed $this->ensureCsrfToken(); } /** * Set security headers */ private function setSecurityHeaders(): void { // Prevent XSS header('X-Content-Type-Options: nosniff'); header('X-Frame-Options: DENY'); header('X-XSS-Protection: 1; mode=block'); // Content Security Policy - Allow external CDNs for development if (getenv('APP_ENV') === 'development' || getenv('APP_DEBUG') === 'true') { header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.tailwindcss.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self'"); } else { header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'"); } // Strict Transport Security (HTTPS only) if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') { header('Strict-Transport-Security: max-age=31536000; includeSubDomains'); } } /** * Sanitize all input data */ private function sanitizeInput(): void { $_GET = $this->sanitizeArray($_GET); $_POST = $this->sanitizeArray($_POST); $_REQUEST = $this->sanitizeArray($_REQUEST); } /** * Sanitize array recursively */ private function sanitizeArray(array $data): array { foreach ($data as $key => $value) { if (is_array($value)) { $data[$key] = $this->sanitizeArray($value); } else { $data[$key] = $this->sanitizeString($value); } } return $data; } /** * Sanitize string input */ public function sanitizeString(string $input): string { // Remove null bytes $input = str_replace(chr(0), '', $input); // HTML encode special characters $input = htmlspecialchars($input, ENT_QUOTES | ENT_HTML5, 'UTF-8'); return $input; } /** * Generate CSRF token */ public function generateCsrfToken(): string { if (!isset($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } return $_SESSION['csrf_token']; } /** * Verify CSRF token */ public function verifyCsrfToken(string $token): bool { if (!isset($_SESSION['csrf_token'])) { return false; } return hash_equals($_SESSION['csrf_token'], $token); } /** * Ensure CSRF token exists */ private function ensureCsrfToken(): void { if (!isset($_SESSION['csrf_token'])) { $this->generateCsrfToken(); } } /** * Get CSRF token name */ public function getCsrfTokenName(): string { return $this->csrfTokenName; } /** * Encrypt data using AES-256-GCM */ public function encrypt(string $data): string { $key = hash('sha256', $this->appKey, true); $iv = random_bytes(16); $ciphertext = openssl_encrypt($data, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag); return base64_encode($iv . $tag . $ciphertext); } /** * Decrypt data using AES-256-GCM */ public function decrypt(string $encryptedData): string { $data = base64_decode($encryptedData); $key = hash('sha256', $this->appKey, true); $iv = substr($data, 0, 16); $tag = substr($data, 16, 16); $ciphertext = substr($data, 32); return openssl_decrypt($ciphertext, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag); } /** * Hash password securely */ public function hashPassword(string $password): string { return password_hash($password, PASSWORD_ARGON2ID); } /** * Verify password */ public function verifyPassword(string $password, string $hash): bool { return password_verify($password, $hash); } /** * Generate secure random string */ public function generateRandomString(int $length = 32): string { return bin2hex(random_bytes($length)); } }