Security Hardening: Phase 1-3 complete

- C1: Hash refresh tokens before DB storage (sha256)
- C2: Remove JWT_SECRET fallback, fail hard if missing
- H1: Enforce HTTP methods per route (405 on mismatch)
- H2: CORS with origin whitelist from CORS_ORIGIN env var
- H3: Redact sensitive fields (tokens, passwords) from logs
- M1: Build HmacMiddleware with replay attack prevention
- M2: Fix rate limiter race condition with flock LOCK_EX
- M3: Guard dd() — suppressed in production
- M4: Remove .env from git tracking, strengthen .gitignore
- I1: Add HSTS header (max-age=31536000)
This commit is contained in:
Hamza-Ayed
2026-05-03 21:06:17 +03:00
parent b33513ebcf
commit 214d96ee8d
11 changed files with 236 additions and 130 deletions

View File

@@ -10,11 +10,11 @@ define('ROOT_PATH', dirname(__DIR__, 2));
define('APP_PATH', ROOT_PATH . '/app');
define('STORAGE_PATH', ROOT_PATH . '/storage');
// 2. Load Environment Loader & Helpers FIRST
// 2. Load Environment & Helpers FIRST
require_once APP_PATH . '/bootstrap/env.php';
require_once APP_PATH . '/helpers/helpers.php';
// 3. Error Reporting (Secure for production - Now we can use env())
// 3. Error Reporting (Secure for production)
if (env('APP_DEBUG', 'false') === 'true') {
error_reporting(E_ALL);
ini_set('display_errors', '1');
@@ -23,36 +23,58 @@ if (env('APP_DEBUG', 'false') === 'true') {
ini_set('display_errors', '0');
}
// 4. Security Headers
// 4. H2 Fix: CORS — Whitelist only known origins
$allowedOrigins = array_filter(array_map('trim', explode(',', env('CORS_ORIGIN', 'https://musadaq.intaleqapp.com'))));
$requestOrigin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array($requestOrigin, $allowedOrigins, true)) {
header("Access-Control-Allow-Origin: {$requestOrigin}");
} else {
// Fallback to first allowed origin (for non-browser API clients)
header("Access-Control-Allow-Origin: " . ($allowedOrigins[0] ?? ''));
}
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization, X-HMAC-Signature, X-Timestamp");
header("Access-Control-Allow-Credentials: true");
header("Vary: Origin");
// Handle CORS preflight
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit;
}
// 5. Security Headers
header("X-Content-Type-Options: nosniff");
header("X-Frame-Options: DENY");
header("X-XSS-Protection: 1; mode=block");
header("Referrer-Policy: strict-origin-when-cross-origin");
header("Strict-Transport-Security: max-age=31536000; includeSubDomains"); // I1 Fix: HSTS
// 5. Intelligent Autoloader (Case-Insensitive for directories)
// 6. Intelligent Autoloader (Case-Insensitive for directories)
spl_autoload_register(function ($class) {
$prefix = 'App\\';
$prefix = 'App\\';
$base_dir = APP_PATH . '/';
$len = strlen($prefix);
if (strncmp($prefix, $class, $len) !== 0) return;
$relative_class = substr($class, $len);
// Normalize path to lowercase for directories, keep filename case
$parts = explode('\\', $relative_class);
$parts = explode('\\', $relative_class);
$filename = array_pop($parts) . '.php';
$dir = strtolower(implode('/', $parts));
$dir = strtolower(implode('/', $parts));
$file = $base_dir . ($dir ? $dir . '/' : '') . $filename;
if (file_exists($file)) {
require $file;
}
});
// 6. Response Utility
// 7. Response Utility
require_once APP_PATH . '/bootstrap/response.php';
// 7. Global Auth Helper
// 8. Global Auth Helper
require_once APP_PATH . '/bootstrap/auth.php';