JezK
Edit File: csrf-security.php
<?php /** * CSRF Security Module * Provides centralized CSRF token generation and validation for Zoho CRM API endpoints */ // Ensure this file is accessed within WordPress if (!defined('ABSPATH')) { define('ABSPATH', dirname(__FILE__) . '/../../../../'); } // Start session if not already started with secure settings if (!session_id() && !headers_sent()) { // Set secure session parameters ini_set('session.cookie_httponly', 1); if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') { ini_set('session.cookie_secure', 1); } ini_set('session.use_only_cookies', 1); ini_set('session.cookie_samesite', 'Strict'); session_start(); } /** * Generates a new CSRF token and stores it in the session * * @return string The generated CSRF token */ function generate_csrf_token() { // Using stronger random bytes (64 bytes = 512 bits) for token $token = bin2hex(random_bytes(64)); $_SESSION['csrf_token'] = $token; $_SESSION['csrf_token_time'] = time(); // Add a hash to verify token integrity $_SESSION['csrf_token_hash'] = hash('sha256', $token . $_SERVER['HTTP_USER_AGENT'] . $_SERVER['REMOTE_ADDR']); return $token; } /** * Validates the CSRF token and referrer * * @param string $token The CSRF token to validate * @return bool True if valid, false otherwise */ function validate_csrf_token($token) { // Check if token exists in session if (!isset($_SESSION['csrf_token']) || !isset($_SESSION['csrf_token_time']) || !isset($_SESSION['csrf_token_hash'])) { return false; } // Check if token has expired (30-minute lifetime instead of 1 hour for better security) if (time() - $_SESSION['csrf_token_time'] > 1800) { return false; } // Validate token if ($token !== $_SESSION['csrf_token']) { return false; } // Validate hash to prevent token manipulation $expected_hash = hash('sha256', $token . $_SERVER['HTTP_USER_AGENT'] . $_SERVER['REMOTE_ADDR']); if ($_SESSION['csrf_token_hash'] !== $expected_hash) { return false; } return true; } /** * Validates that the request came from an allowed domain * * @return bool True if referrer is valid, false otherwise */ function validate_referrer() { // Check if request is coming from your domain $referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''; // List of allowed domains (adjust these to match your actual domains) $allowed_domains = ['authentica.com', 'www.authentica.com']; // Always allow requests from the same server (for testing) if (empty($referer) && isset($_SERVER['SERVER_NAME'])) { return true; // Local request } // Improved validation with more specific domain matching foreach ($allowed_domains as $domain) { $domain_pattern = '/^https?:\/\/(www\.)?' . preg_quote($domain, '/') . '/i'; if (preg_match($domain_pattern, $referer)) { return true; } } return false; } /** * Processes a token generation request * Returns JSON response and exits */ function handle_token_request() { $token = generate_csrf_token(); header('Content-Type: application/json'); header('X-Content-Type-Options: nosniff'); header('X-Frame-Options: DENY'); echo json_encode(['csrf_token' => $token]); exit; } /** * Secures an API endpoint by validating CSRF token and referrer * * @param array $input JSON decoded request body * @return bool True if request is valid, false otherwise */ function secure_api_endpoint($input) { // Check if this is a token generation request if (isset($_GET['action']) && $_GET['action'] === 'get_token') { handle_token_request(); } // Validate referrer if (!validate_referrer()) { header('Content-Type: application/json'); header('X-Content-Type-Options: nosniff'); echo json_encode([ 'error' => 'Invalid request origin', 'http_code' => 403 ]); return false; } // Check if CSRF token exists in request if (!isset($input['csrf_token'])) { header('Content-Type: application/json'); header('X-Content-Type-Options: nosniff'); echo json_encode([ 'error' => 'Something went wrong. Please try again', 'http_code' => 403 ]); return false; } // Validate CSRF token if (!validate_csrf_token($input['csrf_token'])) { header('Content-Type: application/json'); header('X-Content-Type-Options: nosniff'); echo json_encode([ 'error' => 'Something went wrong. Please try again', 'http_code' => 403 ]); return false; } return true; }