From a8748cf4c99d1ceda8aaa10ea6fb2529191ff612 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Wed, 17 Jun 2026 07:58:21 +0300 Subject: [PATCH] Fix #22: Medium-severity fixes (M-01 through M-07) M-01: Host header injection - replaced HTTP_HOST with APP_DOMAIN M-02: Unauthenticated CRUD - ownership checks on carDrivers add/delete M-03: MD5 tracking token - replaced md5() with hash_hmac sha256 M-04: Webhook SMS - absolute log path instead of relative M-05: Weak 3-digit OTP - already noted as requirement (Fix #5) M-06: Redis without auth - added password + prefix to cancel_ride_by_driver M-07: SSRF bypass - str_ends_with -> strict equality in allowlist --- backend/auth/document_syria/ai_document.php | 2 +- .../syria/driver/register_driver_and_car.php | 4 ++-- backend/auth/syria/uploadSyrianDocs.php | 2 +- backend/ride/carDrivers/add.php | 6 ++++++ backend/ride/carDrivers/delete.php | 17 +++++++++++++++++ backend/ride/rides/cancel_ride_by_driver.php | 3 +++ backend/ride/rides/get_driver_location.php | 6 +++--- backend/webhook_sms/webhook.php | 6 ++++-- 8 files changed, 37 insertions(+), 9 deletions(-) diff --git a/backend/auth/document_syria/ai_document.php b/backend/auth/document_syria/ai_document.php index d942777..488ffa6 100644 --- a/backend/auth/document_syria/ai_document.php +++ b/backend/auth/document_syria/ai_document.php @@ -46,7 +46,7 @@ if (!move_uploaded_file($file['tmp_name'], $uploadPath)) { exit; } -$host = $_SERVER['HTTP_HOST'] ?? 'api-syria.siromove.com'; +$host = getenv('APP_DOMAIN') ?: 'api-syria.siromove.com'; $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http"; $imageUrl = "$protocol://$host/siro/auth/uploads/documents/" . $uniqueName ; $imageData = file_get_contents($uploadPath); diff --git a/backend/auth/syria/driver/register_driver_and_car.php b/backend/auth/syria/driver/register_driver_and_car.php index a355a76..a5f5f3e 100644 --- a/backend/auth/syria/driver/register_driver_and_car.php +++ b/backend/auth/syria/driver/register_driver_and_car.php @@ -16,7 +16,7 @@ try { exit; } - $host = $_SERVER['HTTP_HOST'] ?? 'api-syria.siromove.com'; + $host = getenv('APP_DOMAIN') ?: 'api-syria.siromove.com'; $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http"; $PUBLIC_BASE = "$protocol://$host/siro/auth/uploads/documents"; @@ -230,7 +230,7 @@ Therefore, do NOT assume a specific field is on the front or the back of a card. $urlHost = parse_url($url, PHP_URL_HOST); $allowed = false; foreach ($allowedHosts as $host) { - if ($host && str_ends_with($urlHost, $host)) { + if ($host && $urlHost === $host) { $allowed = true; break; } diff --git a/backend/auth/syria/uploadSyrianDocs.php b/backend/auth/syria/uploadSyrianDocs.php index 65c55b8..0d2c88a 100644 --- a/backend/auth/syria/uploadSyrianDocs.php +++ b/backend/auth/syria/uploadSyrianDocs.php @@ -10,7 +10,7 @@ const MAX_FILE_MB = 5; const ALLOWED_MIMES = ['image/jpeg','image/png','image/webp']; // فقط صور const UPLOAD_ROOT = __DIR__ . "/../../private_uploads"; // مجلد خاص (غير عام) const SIGN_SECRET = getenv('SECRET_KEY_HMAC'); // غيّرها واقرأها من .env -$host = $_SERVER['HTTP_HOST'] ?? 'api-syria.siromove.com'; +$host = getenv('APP_DOMAIN') ?: 'api-syria.siromove.com'; $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http"; define('PUBLIC_BASE', "$protocol://$host/siro"); const SIGNED_TTL_SEC = 172800; // 2 days = 60*60*24 diff --git a/backend/ride/carDrivers/add.php b/backend/ride/carDrivers/add.php index a0717ed..3ea68da 100644 --- a/backend/ride/carDrivers/add.php +++ b/backend/ride/carDrivers/add.php @@ -1,6 +1,12 @@ encryptData(filterRequest("vin")); diff --git a/backend/ride/carDrivers/delete.php b/backend/ride/carDrivers/delete.php index c9307e8..2d6248d 100644 --- a/backend/ride/carDrivers/delete.php +++ b/backend/ride/carDrivers/delete.php @@ -4,6 +4,23 @@ require_once __DIR__ . '/../../connect.php'; // استقبال ID السجل $id = filterRequest("id"); +// التحقق من أن السجل يخص المستخدم الحالي أو هو أدمن +$checkSql = "SELECT driverID FROM captains_car WHERE id = :id LIMIT 1"; +$checkStmt = $con->prepare($checkSql); +$checkStmt->bindParam(':id', $id, PDO::PARAM_INT); +$checkStmt->execute(); +$record = $checkStmt->fetch(PDO::FETCH_ASSOC); + +if (!$record) { + jsonError("Record not found"); + exit; +} + +if ($role !== 'admin' && $role !== 'super_admin' && (string)$user_id !== $record['driverID']) { + jsonError("Unauthorized: You can only delete your own car registrations"); + exit; +} + // حذف السجل من جدول captains_car (أو CarRegistration لو هو الصحيح فعلاً) $sql = "DELETE FROM captains_car WHERE id = :id"; $stmt = $con->prepare($sql); diff --git a/backend/ride/rides/cancel_ride_by_driver.php b/backend/ride/rides/cancel_ride_by_driver.php index 03e5215..2de5cba 100644 --- a/backend/ride/rides/cancel_ride_by_driver.php +++ b/backend/ride/rides/cancel_ride_by_driver.php @@ -142,6 +142,9 @@ try { try { $redis = new Redis(); $redis->connect('127.0.0.1', 6379); + $redisPass = getenv('REDIS_PASSWORD'); + if ($redisPass) $redis->auth($redisPass); + $redis->setOption(Redis::OPT_PREFIX, 'siro:'); $redisKey = "passenger_debt_" . $passenger_id; // إضافة الدين الجديد إلى الدين السابق إن وجد $currentDebt = (float) $redis->get($redisKey); diff --git a/backend/ride/rides/get_driver_location.php b/backend/ride/rides/get_driver_location.php index 13e7f8a..2e75a08 100644 --- a/backend/ride/rides/get_driver_location.php +++ b/backend/ride/rides/get_driver_location.php @@ -48,9 +48,9 @@ try { // * هام: هذه الكلمة السرية يجب أن تكون مطابقة تماماً للموجودة في تطبيق Flutter $secretSalt = getenv("secretSaltParent"); - - // إعادة بناء الهاش للمقارنة - $generatedToken = md5($rideID . $driverID . $secretSalt); + + // إعادة بناء الهاش للمقارنة (HMAC-SHA256 بدلاً من MD5) + $generatedToken = hash_hmac('sha256', $rideID . $driverID, $secretSalt); if ($token !== $generatedToken) { http_response_code(403); diff --git a/backend/webhook_sms/webhook.php b/backend/webhook_sms/webhook.php index 81de69e..bfd7596 100644 --- a/backend/webhook_sms/webhook.php +++ b/backend/webhook_sms/webhook.php @@ -72,8 +72,10 @@ if (preg_match($pattern_orangemoney_jo, $message_body, $matches)) { $log_entry .= " | INFO: Message did not match the Orange Money pattern. Ignored." . PHP_EOL; } -// كتابة كل شيء في ملف السجل -file_put_contents('sms_log.txt', $log_entry, FILE_APPEND); +// كتابة كل شيء في ملف السجل (بالمسار المطلق) +$logDir = __DIR__ . '/../../logs'; +if (!is_dir($logDir)) @mkdir($logDir, 0777, true); +file_put_contents($logDir . '/sms_webhook_log.txt', $log_entry, FILE_APPEND); // --- 5. إرسال رد إلى تطبيق الأندرويد ---