diff --git a/backend/core/Auth/RateLimiter.php b/backend/core/Auth/RateLimiter.php index 2f85022..953eb0b 100644 --- a/backend/core/Auth/RateLimiter.php +++ b/backend/core/Auth/RateLimiter.php @@ -29,7 +29,8 @@ class RateLimiter public function check(string $identifier, string $type = 'api'): bool { if (!$this->redis) { - return true; // بدون Redis نمرر (fallback) + // HIGH-01 FIX: fallback مع ملف بدلاً من تمرير كل الطلبات + return $this->fileBasedCheck($identifier, $type); } $limit = self::LIMITS[$type] ?? self::LIMITS['api']; @@ -77,6 +78,47 @@ class RateLimiter { if ($this->redis) { $this->redis->del("rate:{$type}:{$identifier}"); + } else { + // HIGH-01: مسح ملف الفل باك عند إعادة التعيين + $key = self::sanitizeKey("rate:{$type}:{$identifier}"); + $tmpFile = sys_get_temp_dir() . "/rate_{$key}.json"; + if (file_exists($tmpFile)) { + @unlink($tmpFile); + } } } + + // ── Fallback باستخدام ملفات مؤقتة عند تعطل Redis ─────────── + private function fileBasedCheck(string $identifier, string $type): bool + { + $limit = self::LIMITS[$type] ?? self::LIMITS['api']; + $window = $limit['window']; + $max = $limit['requests']; + + $key = self::sanitizeKey("rate:{$type}:{$identifier}"); + $tmpFile = sys_get_temp_dir() . "/rate_{$key}.json"; + $now = time(); + + $data = []; + if (file_exists($tmpFile)) { + $data = json_decode(file_get_contents($tmpFile), true) ?: []; + } + + // تنظيف النوافذ القديمة + $data = array_filter($data, fn($ts) => $ts > ($now - $window)); + + if (count($data) >= $max) { + error_log("[RATE_LIMIT_FB] File-based block: $identifier | type: $type"); + return false; + } + + $data[] = $now; + file_put_contents($tmpFile, json_encode($data)); + return true; + } + + private static function sanitizeKey(string $key): string + { + return preg_replace('/[^a-zA-Z0-9_\-:]/', '_', $key); + } } diff --git a/backend/encrypt_decrypt.php b/backend/encrypt_decrypt.php index 91d4557..9d14618 100644 --- a/backend/encrypt_decrypt.php +++ b/backend/encrypt_decrypt.php @@ -101,6 +101,11 @@ class EncryptionHelper { public function decryptBinary($data) { $decrypted = openssl_decrypt($data, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv); + // CRIT-07 FIX: التحقق من فشل openssl_decrypt + if ($decrypted === false) { + error_log('[CRIT-07] openssl_decrypt failed in decryptBinary'); + throw new Exception('Decryption failed'); + } return $decrypted; } } diff --git a/backend/ride/rides/cron_ride_timeout.php b/backend/ride/rides/cron_ride_timeout.php index 12cf541..d2c0437 100644 --- a/backend/ride/rides/cron_ride_timeout.php +++ b/backend/ride/rides/cron_ride_timeout.php @@ -59,6 +59,7 @@ try { } catch (PDOException $e) { $errorMsg = "❌ [Cleanup Cron] Error: " . $e->getMessage(); error_log($errorMsg); - echo json_encode(["status" => "failure", "message" => $e->getMessage()]); + error_log("[cron_ride_timeout] Error: " . $e->getMessage()); + echo json_encode(["status" => "failure", "message" => "An internal error occurred."]); } ?> \ No newline at end of file diff --git a/backend/ride/rides/getRealTimeHeatmap.php b/backend/ride/rides/getRealTimeHeatmap.php index 77bbe3c..16dd77e 100644 --- a/backend/ride/rides/getRealTimeHeatmap.php +++ b/backend/ride/rides/getRealTimeHeatmap.php @@ -73,7 +73,8 @@ try { echo json_encode(["status" => "success", "data" => $finalData]); } catch (Exception $e) { - echo json_encode(["status" => "failure", "message" => $e->getMessage()]); + error_log("[getRealTimeHeatmap] Error: " . $e->getMessage()); + echo json_encode(["status" => "failure", "message" => "An internal error occurred."]); } function addToGrid(&$grid, $lat, $lng, $precision, $weight) { diff --git a/backend/ride/rides/getRideOrderID.php b/backend/ride/rides/getRideOrderID.php index 7bc828e..57d0e63 100644 --- a/backend/ride/rides/getRideOrderID.php +++ b/backend/ride/rides/getRideOrderID.php @@ -174,6 +174,6 @@ try { } catch (Exception $e) { error_log("API Error: " . $e->getMessage()); http_response_code(500); - echo json_encode(["status" => "failure", "message" => "Server Error: " . $e->getMessage()]); + echo json_encode(["status" => "failure", "message" => "An internal server error occurred."]); } ?> diff --git a/backend/ride/rides/getRideOrderIDNew.php b/backend/ride/rides/getRideOrderIDNew.php index 3aecd1b..e86fd42 100644 --- a/backend/ride/rides/getRideOrderIDNew.php +++ b/backend/ride/rides/getRideOrderIDNew.php @@ -143,6 +143,6 @@ try { } catch (Exception $e) { error_log("API Error: " . $e->getMessage()); http_response_code(500); - echo json_encode(["status" => "failure", "message" => "Server Error: " . $e->getMessage()]); + echo json_encode(["status" => "failure", "message" => "An internal server error occurred."]); } ?> \ No newline at end of file diff --git a/backend/ride/rides/getRideStatusFromStartApp.php b/backend/ride/rides/getRideStatusFromStartApp.php index 3059949..3039d06 100644 --- a/backend/ride/rides/getRideStatusFromStartApp.php +++ b/backend/ride/rides/getRideStatusFromStartApp.php @@ -88,6 +88,7 @@ try { ]); } catch (Exception $e) { - echo json_encode(["status" => "failure", "message" => $e->getMessage()]); + error_log("[getRideStatusFromStartApp] Error: " . $e->getMessage()); + echo json_encode(["status" => "failure", "message" => "An internal error occurred."]); } ?> \ No newline at end of file diff --git a/walletintaleq.intaleq.xyz/v2/main/encrypt_decrypt.php b/walletintaleq.intaleq.xyz/v2/main/encrypt_decrypt.php index b34e96f..f8b36e6 100755 --- a/walletintaleq.intaleq.xyz/v2/main/encrypt_decrypt.php +++ b/walletintaleq.intaleq.xyz/v2/main/encrypt_decrypt.php @@ -88,6 +88,11 @@ class EncryptionHelper { public function decryptBinary($data) { $decrypted = openssl_decrypt($data, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv); + // CRIT-07 FIX: التحقق من فشل openssl_decrypt + if ($decrypted === false) { + error_log('[CRIT-07] openssl_decrypt failed in decryptBinary'); + throw new Exception('Decryption failed'); + } return $decrypted; } } diff --git a/walletintaleq.intaleq.xyz/v2/main/loginWallet.php b/walletintaleq.intaleq.xyz/v2/main/loginWallet.php index e365a95..e3758c9 100755 --- a/walletintaleq.intaleq.xyz/v2/main/loginWallet.php +++ b/walletintaleq.intaleq.xyz/v2/main/loginWallet.php @@ -36,6 +36,12 @@ header('Content-Type: application/json'); header("Access-Control-Allow-Origin: https://wallet.sefer.live"); // Replace * with your Flutter app's origin header("Access-Control-Allow-Methods: POST, OPTIONS"); header("Access-Control-Allow-Headers: Content-Type, Authorization"); +// MED FIX: إضافة Security Headers +header('X-Content-Type-Options: nosniff'); +header('X-Frame-Options: DENY'); +header('Strict-Transport-Security: max-age=31536000; includeSubDomains'); +header("Referrer-Policy: strict-origin-when-cross-origin"); +header("X-XSS-Protection: 1; mode=block"); // Handle preflight OPTIONS requests if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { @@ -123,13 +129,13 @@ $hmac = hash_hmac('sha256', $id, getenv('SECRET_KEY_HMAC')); } } catch (InvalidArgumentException $e) { - // Handle input validation errors - http_response_code(400); // Bad Request - Client-side error - // error_log("Input validation error: " . $e->getMessage()); // Log for debugging - echo json_encode(['error' => $e->getMessage()]); // Specific error message + // HIGH-05 FIX: لا تكشف رسائل الخطأ من الاستثناءات مباشرة + error_log("Input validation error: " . $e->getMessage()); + http_response_code(400); + echo json_encode(['error' => 'Invalid request parameters.']); } catch (Exception $e) { - // Handle other exceptions (e.g., JWT encoding errors) - http_response_code(500); // Internal Server Error - // error_log("Server error: " . $e->getMessage()); // Log for debugging - echo json_encode(['error' => 'An unexpected error occurred.']); // Generic message -} \ No newline at end of file + // HIGH-05 FIX: لا تكشف رسائل الخطأ الداخلية + error_log("Server error: " . $e->getMessage()); + http_response_code(500); + echo json_encode(['error' => 'An unexpected error occurred.']); +} diff --git a/walletintaleq.intaleq.xyz/v2/main/loginWalletAdmin.php b/walletintaleq.intaleq.xyz/v2/main/loginWalletAdmin.php index 53bc8e7..7af4789 100755 --- a/walletintaleq.intaleq.xyz/v2/main/loginWalletAdmin.php +++ b/walletintaleq.intaleq.xyz/v2/main/loginWalletAdmin.php @@ -70,14 +70,18 @@ try { $user = $stmt->fetch(); if (!$user) { - // إذا لم يكن موجوداً، نتحقق من كلمة السر العامة للأدمن كخيار أخير - if ($id === 'admin' && $password === $passwordnewpassenger) { - // السماح بالدخول كأدمن عام - } else { - http_response_code(403); - echo json_encode(['error' => 'User not found']); - exit; - } + // ⚠️ CRIT-01 FIX: إزالة backdoor الدخول بكلمة سر plaintext + // لا يمكن الدخول إلا عبر مستخدمين مسجلين في قاعدة البيانات + http_response_code(403); + echo json_encode(['error' => 'User not found']); + exit; + } + + // التحقق من كلمة السر باستخدام password_verify (آمن) + if (!password_verify($password, $user['password'])) { + http_response_code(403); + echo json_encode(['error' => 'Invalid credentials']); + exit; } // --- إنشاء JWT --- @@ -102,6 +106,8 @@ try { http_response_code(200); } catch (Exception $e) { + // HIGH-05 FIX: لا تكشف رسائل الخطأ التفصيلية + error_log('[loginWalletAdmin] Error: ' . $e->getMessage()); http_response_code(500); - echo json_encode(['error' => 'Unexpected error occurred: ' . $e->getMessage()]); + echo json_encode(['error' => 'An internal error occurred. Please try again later.']); } diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/cliq/verify_payment_ai.php b/walletintaleq.intaleq.xyz/v2/main/ride/cliq/verify_payment_ai.php index 6381727..126849f 100644 --- a/walletintaleq.intaleq.xyz/v2/main/ride/cliq/verify_payment_ai.php +++ b/walletintaleq.intaleq.xyz/v2/main/ride/cliq/verify_payment_ai.php @@ -70,6 +70,6 @@ try { } catch (Exception $e) { error_log("Error in cliq verify: " . $e->getMessage()); - echo json_encode(["status" => "error", "message" => "Server error: " . $e->getMessage()]); + echo json_encode(["status" => "error", "message" => "Server error occurred."]); } ?> diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/convertBudgetToPoints.php b/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/convertBudgetToPoints.php index f4799c6..083679e 100644 --- a/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/convertBudgetToPoints.php +++ b/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/convertBudgetToPoints.php @@ -29,10 +29,10 @@ try { } // 2. Generate unique tokens - $paymentID1 = "budget2pt_" . time() . rand(1000, 9999); - $paymentID2 = "pt2budget_" . time() . rand(1000, 9999); - $token1 = md5(uniqid("b1", true)); - $token2 = md5(uniqid("b2", true)); + $paymentID1 = "budget2pt_" . time() . bin2hex(random_bytes(4)); + $paymentID2 = "pt2budget_" . time() . bin2hex(random_bytes(4)); + $token1 = bin2hex(random_bytes(32)); + $token2 = bin2hex(random_bytes(32)); // 3. Deduct from budget (payments) $deductAmount = -$amount; @@ -62,6 +62,7 @@ try { } catch (Exception $e) { $con->rollBack(); - echo json_encode(['status' => 'error', 'message' => 'Database transaction failed: ' . $e->getMessage()]); + error_log('[convertBudgetToPoints] Error: ' . $e->getMessage()); + echo json_encode(['status' => 'error', 'message' => 'An internal error occurred.']); } ?> diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/transfer.php b/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/transfer.php index 9c3a8d4..1b8d628 100644 --- a/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/transfer.php +++ b/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/transfer.php @@ -124,6 +124,7 @@ try { } catch (Exception $e) { $con->rollBack(); - echo json_encode(['status' => 'error', 'message' => 'Database transaction failed: ' . $e->getMessage()]); + error_log('[transfer] Error: ' . $e->getMessage()); + echo json_encode(['status' => 'error', 'message' => 'An internal error occurred.']); } ?>