From c35a3ef66d6fc0adf1bb178b9cf918bcbf79f151 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Sat, 2 May 2026 16:39:01 +0300 Subject: [PATCH] service add APP_SIGNATURE_SERVICE 3 --- core/Auth/JwtService.php | 64 ++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/core/Auth/JwtService.php b/core/Auth/JwtService.php index 36a0f40..1494c0a 100644 --- a/core/Auth/JwtService.php +++ b/core/Auth/JwtService.php @@ -168,33 +168,30 @@ class JwtService self::abort(401, 'Invalid token issuer: expected ' . $this->issuer . ' but got ' . ($decoded->iss ?? 'none')); } - // 3.1 App Signature Verification (Security Layer) - $appSignature = $_SERVER['HTTP_X_APP_SIGNATURE'] ?? null; - if ($appSignature === null && function_exists('getallheaders')) { - $headers = array_change_key_case(getallheaders(), CASE_LOWER); - $appSignature = $headers['x-app-signature'] ?? null; - } - - // قائمة البصمات المعتمدة لكل تطبيق (يجب تعبئتها من ملف .env) - // APP_SIGNATURE_SERVICE, APP_SIGNATURE_DRIVER, APP_SIGNATURE_PASSENGER + // 3.1 App Signature Verification (Service Only) $role = $decoded->role ?? 'unknown'; - $envKey = 'APP_SIGNATURE_' . strtoupper($role); - $expectedSignature = getenv($envKey) ?: getenv('APP_SIGNATURE_HASH'); - - if (!empty($expectedSignature)) { - if ($appSignature === null || !hash_equals($expectedSignature, $appSignature)) { - error_log("[SECURITY_ERROR] App Signature Mismatch/Missing! Role: $role | Expected: $expectedSignature | Got: " . ($appSignature ?? 'NONE') . " | User: $userId"); - - // الحظر النهائي: إذا كانت البصمة خاطئة، نرفض الطلب فوراً - self::abort(403, 'App integrity check failed. Please update your app.'); + if ($role === 'service') { + $appSignature = $_SERVER['HTTP_X_APP_SIGNATURE'] ?? null; + if ($appSignature === null && function_exists('getallheaders')) { + $headers = array_change_key_case(getallheaders(), CASE_LOWER); + $appSignature = $headers['x-app-signature'] ?? null; + } + + // نقبل بصمة الـ Release أو الـ Debug + $allowedSignatures = array_filter([ + getenv('APP_SIGNATURE_SERVICE_RELEASE'), + getenv('APP_SIGNATURE_SERVICE_DEBUG'), + getenv('APP_SIGNATURE_HASH') // Fallback + ]); + + if (!empty($allowedSignatures)) { + if ($appSignature === null || !in_array($appSignature, $allowedSignatures)) { + error_log("[SECURITY_ERROR] App Signature Mismatch! Role: $role | Got: " . ($appSignature ?? 'NONE') . " | User: " . ($decoded->user_id ?? 'unknown')); + self::abort(403, 'App integrity check failed. Please use the official app.'); + } } - } else { - // في حال لم يتم ضبط البصمة لهذا النوع من المستخدمين بعد، نسجلها فقط لتسهيل الإعداد - error_log("[SECURITY_INFO] Incoming App Signature for $role: " . ($appSignature ?? 'NONE') . " | User: $userId"); } - - // 4. User ID $userId = $decoded->user_id ?? $decoded->sub ?? null; if (!$userId) { @@ -238,13 +235,11 @@ class JwtService } if ($fpInToken === null || $fpHeader === null) { - $allHeaders = json_encode(getallheaders()); error_log("[SECURITY] Fingerprint missing | user: $userId | fpInToken: " . ($fpInToken ?? 'NULL') . " | fpHeader: " . ($fpHeader ?? 'NULL') . " | Headers: $allHeaders"); self::abort(403, 'Device verification required'); } - $expected = hash('sha256', $fpHeader . $this->fpPepper); if (!hash_equals($expected, $fpInToken)) { error_log("[SECURITY] Device mismatch | user: $userId | IP: " . ($_SERVER['REMOTE_ADDR'] ?? '?')); @@ -252,27 +247,25 @@ class JwtService } } - // 8. HMAC — مطلوب للعمليات الحساسة (Wallet/Logout) + // 8. HMAC Verification (Derived Secret for Service) $hmacHeader = $_SERVER['HTTP_X_HMAC_AUTH'] ?? null; if ($hmacHeader !== null) { $timestamp = $_SERVER['HTTP_X_TIMESTAMP'] ?? ''; $nonce = $_SERVER['HTTP_X_NONCE'] ?? ''; $body = file_get_contents('php://input') ?: ''; - // نشتق مفتاح الـ HMAC الخاص بهذا المستخدم (نفس المعادلة في login.php) - $derivedSecret = hash_hmac('sha256', (string)$userId, $this->hmacSecret); - - // التوقيع يضم الـ Body + Timestamp + Nonce لمنع التكرار والتلاعب + // اشتقاق مفتاح الـ HMAC الخاص بهذا المستخدم + $userSecret = hash_hmac('sha256', (string)$userId, $this->hmacSecret); + + // المعادلة الموحدة: Body + Timestamp + Nonce $payloadToSign = $body . $timestamp . $nonce; - $expectedHmac = hash_hmac('sha256', $payloadToSign, $derivedSecret); - + $expectedHmac = hash_hmac('sha256', $payloadToSign, $userSecret); if (!hash_equals($expectedHmac, $hmacHeader)) { - error_log("[SECURITY] HMAC mismatch | user: $userId | IP: " . ($_SERVER['REMOTE_ADDR'] ?? '?')); + $debugMsg = "User: $userId | Expected: $expectedHmac | Got: $hmacHeader | DerivedSecret: $userSecret | PayloadToSign: " . strlen($payloadToSign) . " bytes | Body: '$body' | TS: '$timestamp' | Nonce: '$nonce'"; + error_log("[SECURITY] HMAC mismatch | " . $debugMsg); self::abort(403, 'Invalid HMAC signature'); } - - } return $decoded; @@ -307,7 +300,6 @@ class JwtService } private static function abort(int $code, string $message) - { error_log("[JWT_AUTH_FAILED] Code: $code | Message: $message | IP: " . ($_SERVER['REMOTE_ADDR'] ?? '?') . " | URI: " . ($_SERVER['REQUEST_URI'] ?? '?')); http_response_code($code);