# 🛡️ التقرير الأمني الشامل - Siro Application ## Pure PHP Backend + Flutter Mobile Application **تاريخ التقرير:** 15 يونيو 2026 **المُقيّم:** Senior Penetration Tester / Security Architect **النسخة:** v1.0 **التصنيف:** خاص وسري --- ## 📊 ملخص التقرير | البيان | القيمة | |--------|--------| | **إجمالي الثغرات المكتشفة** | 17 | | **🔴 حرجة (Critical)** | 5 | | **🟠 عالية (High)** | 6 | | **🟡 متوسطة (Medium)** | 4 | | **🟢 منخفضة (Low)** | 2 | | **درجة الأمان الإجمالية** | **2.5 / 10** 🔴 | | **نقاط القوة** | استخدام Prepared Statements في معظم الاستعلامات، وجود Rate Limiting، استخدام JWT مع JTI | | **نقاط الضعف الرئيسية** | حقن SQL في `functions.php`، مفاتيح مشفرة Hardcoded، IV ثابت في AES-CBC، كود Debug معروض | --- ## 🔴 الثغرات الحرجة (Critical) --- ### [C-01] — حقن SQL في دالة `findBestDrivers` | المعلومة | التفصيل | |---------|---------| | **الفئة** | SQL Injection | | **الخطورة** | 🔴 حرجة | | **درجة CVSS** | 9.8/10 | | **CWE** | CWE-89 | | **الملف المتأثر** | `backend/functions.php` | | **السطر المتأثر** | 98-128 | **📌 وصف الثغرة:** يتم استخدام متغير `$carType` مباشرة في استعلام SQL بدون Prepared Statement أو تعقيم. على الرغم من وجود `switch` يحدد القيم، إلا أن القيمة الافتراضية في `default` والأهم أن `$carType` يتم تمريرها من الـ Request مباشرة عبر `add_ride.php` بدون فلترة قبل الوصول إلى هذه الدالة. المهاجم يمكنه تجاوز switch statement عبر إضافة parameters في الـ POST. **🔍 الكود الضعيف:** ```php $carType = trim($carType); switch ($carType) { case 'Comfort': $sql .= " AND cr.vehicle_category_id = $CAT_CAR AND CAST(TRIM(cr.year) AS UNSIGNED) > 2017 "; break; case 'Lady': $femaleHash = 'bQ6yWJ2EVXKZooHdGclvmFiDlZCM8UYeO+ILFjDUvpQ='; $sql .= " AND cr.vehicle_category_id = $CAT_CAR AND d.gender = '$femaleHash' "; break; // ... باقي الحالات default: $sql .= " AND cr.vehicle_category_id = $CAT_CAR AND CAST(TRIM(cr.year) AS UNSIGNED) > 2000 "; break; } ``` **💥 Proof of Concept (PoC):** ``` POST /siro/ride/rides/add_ride.php HTTP/1.1 Host: api.siromove.com Content-Type: application/x-www-form-urlencoded Authorization: Bearer passenger_id=123&start_location=35.0,35.0&end_location=36.0,36.0&price=10&price_token=&carType=Comfort' OR '1'='1' -- -&start_name=test&end_name=test&distance=10&duration_text=5min ``` هذا سيجعل الـ SQL كالتالي: ```sql AND cr.vehicle_category_id = 1 AND CAST(TRIM(cr.year) AS UNSIGNED) > 2017 OR '1'='1' -- - ``` **🎯 تأثير الاستغلال:** - تسريب جميع بيانات السائقين (tokens, IDs, locations, genders) - استغلال الثغرة لتعديل أو حذف بيانات - اختراق كامل لقاعدة البيانات **✅ الحل المقترح:** ```php $carType = trim($carType); $allowedTypes = ['Comfort', 'Mishwar Vip', 'Scooter', 'Pink Bike', 'Electric', 'Lady', 'Van', 'Awfar Car', 'Fixed Price', 'Speed', 'Rayeh Gai']; if (!in_array($carType, $allowedTypes, true)) { $carType = 'Speed'; // default آمن } // أو استخدام switch مع prepared statement switch ($carType) { case 'Lady': $femaleHash = 'bQ6yWJ2EVXKZooHdGclvmFiDlZCM8UYeO+ILFjDUvpQ='; $sql .= " AND cr.vehicle_category_id = ? AND d.gender = ? "; $params[] = $CAT_CAR; $params[] = $femaleHash; break; // ... باقي الحالات مع bind parameters } ``` **📚 المراجع:** - OWASP: https://owasp.org/www-community/attacks/SQL_Injection - CWE: https://cwe.mitre.org/data/definitions/89.html --- ### [C-02] — Hardcoded Internal Key Paths مع Exposure كامل للنظام | المعلومة | التفصيل | |---------|---------| | **الفئة** | Security Misconfiguration / Hardcoded Secrets | | **الخطورة** | 🔴 حرجة | | **درجة CVSS** | 9.3/10 | | **CWE** | CWE-798, CWE-312 | | **الملف المتأثر** | جميع الملفات التالية | | **السطر المتأثر** | متعدد | **📌 وصف الثغرة:** المفاتيح الداخلية ومساراتها ثابتة في الكود المصدر (Hardcoded). هذا يعني أن أي شخص لديه access للكود يمكنه الوصول للمفاتيح. بالإضافة لذلك، المسار `/home/siro-api/.internal_socket_key` و `/home/siro-api/.secret_key` و `/home/siro-api/.enckey` كلها ثابتة ومكتشفة. لو تم اختراق السيرفر بأي طريقة، كل المفاتيح مكشوفة. **🔍 الكود الضعيف:** ```php // في files.php: $INTERNAL_KEY = trim((string)@file_get_contents('/home/siro-api/.internal_socket_key')); // في JwtService.php: $this->secretKey = trim(file_get_contents('/home/siro-api/.secret_key')); // في encrypt_decrypt.php: $key = trim(file_get_contents('/home/siro-api/.enckey')); ``` **💥 Proof of Concept (PoC):** ```bash # إذا تم اختراق السيرفر بأي طريقة (مثل RFI, LFI, SSRF) curl http://target-server/home/siro-api/.secret_key curl http://target-server/home/siro-api/.enckey # أو عبر path traversal في upload POST /siro/uploadImagePortrate.php HTTP/1.1 # ... محاولة قراءة المفاتيح من المجلد ``` **🎯 تأثير الاستغلال:** - توقيع JWT tokens مزيفة - فك تشفير جميع البيانات المشفرة في قاعدة البيانات - التصيد كأي مستخدم في النظام - الدخول للسيرفرات الداخلية **✅ الحل المقترح:** ```php // استخدام getenv بدلاً من file_get_contents $this->secretKey = getenv('JWT_SECRET_KEY') ?: ''; // مع تخزين المفتاح في .env فقط وليس في الكود // وتأكد من أن ملف .env خارج الـ DocumentRoot ``` **📚 المراجع:** - OWASP: https://owasp.org/www-project-top-ten/2017/A3_2017-Sensitive_Data_Exposure - CWE: https://cwe.mitre.org/data/definitions/798.html --- ### [C-03] — ثغرة في `upload_audio.php` - رفع ملفات بدون مصادقة | المعلومة | التفصيل | |---------|---------| | **الفئة** | Unrestricted File Upload / Missing Authentication | | **الخطورة** | 🔴 حرجة | | **درجة CVSS** | 9.0/10 | | **CWE** | CWE-434, CWE-306 | | **الملف المتأثر** | `backend/upload_audio.php` | | **السطر المتأثر** | 1-68 (الكامل) | **📌 وصف الثغرة:** ملف `upload_audio.php` لا يقوم بأي تحقق من JWT أو أي Authentication. لا يوجد Rate Limiting. كما أن اسم الملف النهائي يتم بناؤه من اسم الملف الأصلي بدون تعقيم كافٍ. الامتداد لا يتم التحقق منه أمنياً. **🔍 الكود الضعيف:** ```php $audio_name = $audio_file['name']; $audio_extension = pathinfo($audio_name, PATHINFO_EXTENSION); // التحقق من الامتداد فقط - بدون التحقق الحقيقي if (!in_array($audio_extension, array('m4a', 'mp3', 'wav'))) { echo json_encode(array('status' => 'The audio file is not a valid format.')); exit; } // اسم الملف النهائي: الاسم الأصلي + الامتداد $new_filename = $audio_name . '.' . $audio_extension; $target_file = $target_dir . $new_filename; ``` **💥 Proof of Concept (PoC):** ```bash # رفع ملف PHP curl -X POST https://api.siromove.com/siro/upload_audio.php \ -F "audio=@shell.php;filename=shell.php" \ -F "passengerId=1" # أو path traversal في اسم الملف curl -X POST https://api.siromove.com/siro/upload_audio.php \ -F "audio=@test.php;filename=../../shell.php" ``` **🎯 تأثير الاستغلال:** - رفع Web Shell والتحكم الكامل بالسيرفر - تنفيذ أوامر عشوائية - الوصول لقاعدة البيانات وجميع المفاتيح **✅ الحل المقترح:** ```php // إضافة Authentication require_once __DIR__ . '/connect.php'; // إضافة Rate Limiting $limiter = new RateLimiter($redis); $limiter->enforce(RateLimiter::identifier(), 'upload'); // استخدام أسماء ملفات عشوائية $new_filename = bin2hex(random_bytes(16)) . '.' . $audio_extension; // تحقق إضافي من MIME type باستخدام finfo $finfo = new finfo(FILEINFO_MIME_TYPE); $mimeType = $finfo->file($audio_file['tmp_name']); $allowedMimes = ['audio/mp4', 'audio/mpeg', 'audio/wav', 'audio/x-m4a', 'audio/ogg']; if (!in_array($mimeType, $allowedMimes, true)) { exit(json_encode(['status' => 'Invalid file type'])); } ``` **📚 المراجع:** - OWASP: https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload - CWE: https://cwe.mitre.org/data/definitions/434.html --- ### [C-04] — Information Disclosure عبر Debug Mode وملفات Logs | المعلومة | التفصيل | |---------|---------| | **الفئة** | Information Disclosure / Security Misconfiguration | | **الخطورة** | 🔴 حرجة | | **درجة CVSS** | 8.6/10 | | **CWE** | CWE-200, CWE-532 | | **الملف المتأثر** | `backend/core/bootstrap.php` | | **السطر المتأثر** | 11-19 | **📌 وصف الثغرة:** في ملف `bootstrap.php`، الـ debug mode مضبوط على `true` في الإنتاج. هذا يعرض أخطاء PHP التفصيلية للمستخدمين، والتي قد تحتوي على مسارات الملفات، أسماء قواعد البيانات، وهيكلية الكود. **🔍 الكود الضعيف:** ```php $debugMode = true; // ← يجب أن تكون false في الإنتاج! if ($debugMode) { error_reporting(E_ALL); ini_set('display_errors', '1'); } else { error_reporting(0); ini_set('display_errors', '0'); } ``` **🎯 تأثير الاستغلال:** - تسريب هيكلية قاعدة البيانات - تسريب مسارات الملفات الكاملة - تسريب معلومات الـ DB credentials في حال حدوث خطأ - تسهيل هجمات أكثر تقدماً **✅ الحل المقترح:** ```php // استخدام متغير بيئة لتحديد الـ debug mode $debugMode = getenv('APP_DEBUG') === 'true'; if ($debugMode) { error_reporting(E_ALL); ini_set('display_errors', '1'); } else { error_reporting(0); ini_set('display_errors', '0'); ini_set('log_errors', '1'); } ``` **📚 المراجع:** - OWASP: https://owasp.org/www-project-top-ten/2017/A6_2017-Security_Misconfiguration - CWE: https://cwe.mitre.org/data/definitions/200.html --- ### [C-05] — ثغرة في `encrypt_decrypt.php` - IV ثابت مع AES-256-CBC | المعلومة | التفصيل | |---------|---------| | **الفئة** | Cryptographic Vulnerability | | **الخطورة** | 🔴 حرجة | | **درجة CVSS** | 8.0/10 | | **CWE** | CWE-329, CWE-330 | | **الملف المتأثر** | `backend/encrypt_decrypt.php` | | **السطر المتأثر** | 10-11, 44, 56, 73-92 | **📌 وصف الثغرة:** يستخدم الكود IV (Initialization Vector) ثابت لجميع عمليات التشفير في نمط CBC. هذا يضعف التشفير بشكل كبير ويجعله عرضة لهجمات مثل Chosen Plaintext Attack (CPA). كما أن المفتاح يتم جلبه من ملف خارج الـ DocumentRoot ولكن اسم الملف ثابت معروف. **🔍 الكود الضعيف:** ```php $key = trim(file_get_contents('/home/siro-api/.enckey')); $iv = getenv('initializationVector'); // 16 bytes — IV ثابت public function encryptData($plainText) { $plainText = mb_convert_encoding($plainText, 'UTF-8'); $paddedText = $this->addPadding($plainText); $encrypted = openssl_encrypt($paddedText, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv); return base64_encode($encrypted); } ``` **🎯 تأثير الاستغلال:** - فك تشفير البيانات إذا تم الحصول على زوج plaintext/ciphertext - هجمات الـ ciphertext manipulation - إعادة استخدام IV يسمح بكشف الأنماط في البيانات المشفرة **✅ الحل المقترح:** ```php // استخدام AES-256-GCM بدلاً من CBC (موجود بالفعل في EncryptionHelper.php الجديد) // تأكد من أن جميع التطبيقات تستخدم EncryptionHelper الجديد public function encryptData(string $plainText): string { $iv = random_bytes(12); // IV جديد لكل عملية تشفير $tag = ''; $encrypted = openssl_encrypt($plainText, 'aes-256-gcm', $this->key, OPENSSL_RAW_DATA, $iv, $tag); return base64_encode($iv . $tag . $encrypted); } ``` **📚 المراجع:** - OWASP: https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html - CWE: https://cwe.mitre.org/data/definitions/329.html --- ## 🟠 الثغرات عالية الخطورة (High) --- ### [H-01] — SSRF (Server-Side Request Forgery) | المعلومة | التفصيل | |---------|---------| | **الفئة** | SSRF | | **الخطورة** | 🟠 عالية | | **درجة CVSS** | 7.5/10 | | **CWE** | CWE-918 | | **الملف المتأثر** | `backend/functions.php` | | **السطر المتأثر** | 23-42, 44-157, 159-211, 217-253, 261-307, 334-355 | **📌 وصف الثغرة:** يتم استخدام `curl` مع عناوين IP ثابتة داخلية `http://188.68.36.205:2021` و `http://188.68.36.205:3031`. هذا يسمح بإعادة توجيه الهجمات إلى السيرفرات الداخلية. في حال تم اختراق أي endpoint يمكن إعادة توجيه الـ requests لفحص الشبكة الداخلية. **🔍 الكود الضعيف:** ```php $url = "http://188.68.36.205:2021"; $postData = ['action' => $action, ...$data]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); curl_exec($ch); ``` **🎯 تأثير الاستغلال:** - فحص ports داخلية - مهاجمة خدمات داخلية (Redis, MySQL, etc.) - تجاوز الجدران النارية **✅ الحل المقترح:** ```php // إضافة allowlist لعناوين URL $allowedUrls = ['http://188.68.36.205:2021', 'http://188.68.36.205:3031']; if (!in_array($url, $allowedUrls, true)) { error_log("[SSRF_BLOCKED] Attempted connection to: $url"); return false; } // استخدام DNS بدلاً من IP مباشر // وإضافة firewall rules لتقييد الوصول ``` **📚 المراجع:** - OWASP: https://owasp.org/www-community/attacks/Server_Side_Request_Forgery - CWE: https://cwe.mitre.org/data/definitions/918.html --- ### [H-02] — HMAC Debug Information Disclosure في JwtService | المعلومة | التفصيل | |---------|---------| | **الفئة** | Information Disclosure | | **الخطورة** | 🟠 عالية | | **درجة CVSS** | 7.5/10 | | **CWE** | CWE-209 | | **الملف المتأثر** | `backend/core/Auth/JwtService.php` | | **السطر المتأثر** | 268-271 | **📌 وصف الثغرة:** عند فشل التحقق من HMAC، يتم إرجاع معلومات حساسة جداً للمستخدم مثل الـ derived secret والمفاتيح (ولو بشكل جزئي). هذا يسمح للمهاجم بجمع معلومات عن نظام التوقيع. **🔍 الكود الضعيف:** ```php if (!hash_equals($expectedHmac, $hmacHeader)) { $debugMsg = "User: $userId | Expected: $expectedHmac | Got: $hmacHeader | DerivedSecret: $userSecret | MasterSecret(4): " . substr($this->hmacSecret, 0, 4) . "..."; http_response_code(403); echo json_encode(['error' => 'HMAC_DEBUG', 'debug' => $debugMsg]); exit; } ``` **💥 Proof of Concept (PoC):** ``` POST /any-endpoint HTTP/1.1 X-HMAC-Auth: invalid_hmac X-Timestamp: 123456 X-Nonce: test Response: {"error":"HMAC_DEBUG","debug":"User: ... | MasterSecret(4): S3cr..."} ``` **🎯 تأثير الاستغلال:** - تسريب أول 4 أحرف من المفتاح الرئيسي (Master Secret) - تسريب الـ Derived Secret - تسهيل هجمات Brute Force على HMAC secret **✅ الحل المقترح:** ```php if (!hash_equals($expectedHmac, $hmacHeader)) { error_log("[SECURITY] HMAC mismatch | User: $userId"); http_response_code(403); echo json_encode(['error' => 'Request verification failed']); exit; } ``` **📚 المراجع:** - OWASP: https://owasp.org/www-community/attacks/Information_disclosure - CWE: https://cwe.mitre.org/data/definitions/209.html --- ### [H-03] — CORS Misconfiguration في Admin Login | المعلومة | التفصيل | |---------|---------| | **الفئة** | CORS Misconfiguration | | **الخطورة** | 🟠 عالية | | **درجة CVSS** | 7.3/10 | | **CWE** | CWE-942 | | **الملف المتأثر** | `backend/loginAdmin.php` | | **السطر المتأثر** | 9 | **📌 وصف الثغرة:** يسمح Admin login بأي Origin عبر `*` fallback. هذا يسمح لأي موقع ضابط بعمل Cross-Origin requests وإرسال بيانات المصادقة. **🔍 الكود الضعيف:** ```php header("Access-Control-Allow-Origin: " . (getenv('ALLOWED_ORIGIN') ?: '*')); ``` **🎯 تأثير الاستغلال:** - هجمات CSRF - تسريب بيانات المصادقة من تطبيقات ضارة - استهداف المسؤولين عبر Social Engineering **✅ الحل المقترح:** ```php $allowedOrigin = getenv('ALLOWED_ORIGIN') ?: 'https://admin.siromove.com'; header("Access-Control-Allow-Origin: " . $allowedOrigin); header("Access-Control-Allow-Credentials: true"); ``` **📚 المراجع:** - OWASP: https://owasp.org/www-community/attacks/CORS_OriginHeaderScrutiny - CWE: https://cwe.mitre.org/data/definitions/942.html --- ### [H-04] — Weak Encryption في Flutter (IV ثابت مع AES-CBC) | المعلومة | التفصيل | |---------|---------| | **الفئة** | Cryptographic Vulnerability | | **الخطورة** | 🟠 عالية | | **درجة CVSS** | 7.4/10 | | **CWE** | CWE-329 | | **الملف المتأثر** | `siro_rider/lib/controller/functions/encrypt_decrypt.dart` | | **السطر المتأثر** | 43-53 | **📌 وصف الثغرة:** يستخدم Flutter AES-CBC مع IV ثابت يتم جلبه من الـ Env في التطبيق. هذا يسمح بفك التشفير إذا تم الحصول على الـ key (والذي هو أيضاً في الـ Env). **🔍 الكود الضعيف:** ```dart final encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc)); final encrypted = encrypter.encrypt(plainText, iv: iv); return encrypted.base64; ``` **🎯 تأثير الاستغلال:** - فك تشفير البيانات إذا تم الوصول للتطبيق (Root/Jailbreak) - هجمات الـ Chosen Plaintext - كشف الأنماط في البيانات **✅ الحل المقترح:** ```dart // استخدام GCM mode بدلاً من CBC مع IV عشوائي import 'dart:math'; final iv = encrypt.IV.fromLength(12); // GCM needs 12 bytes IV final encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.gcm)); final encrypted = encrypter.encrypt(plainText, iv: iv); ``` **📚 المراجع:** - OWASP MASTG: https://mas.owasp.org/MASTG/iOS/0x06d-Testing-Data-Storage/ - CWE: https://cwe.mitre.org/data/definitions/329.html --- ### [H-05] — Server-Side Pricing Logic يمكن التحايل عليه | المعلومة | التفصيل | |---------|---------| | **الفئة** | Business Logic Vulnerability | | **الخطورة** | 🟠 عالية | | **درجة CVSS** | 7.2/10 | | **CWE** | CWE-841 | | **الملف المتأثر** | `backend/ride/rides/add_ride.php` | | **السطر المتأثر** | 57-68, 96-144 | **📌 وصف الثغرة:** على الرغم من وجود `price_token` للتوقيع على الأسعار، إلا أن بعض الحقول الأخرى مثل `distance` و `duration_text` لا يتم التحقق منها في الـ token، مما يسمح بالتلاعب ببيانات الرحلة. **🔍 الكود الضعيف:** ```php $distance = filterRequest("distance"); // ... $payload[11] = (string) $distance; $payload[15] = (string) $duration_text; ``` **🎯 تأثير الاستغلال:** - التلاعب بمسافة الرحلة لعرض سعر أقل - التلاعب بمدة الرحلة - خداع السائقين ببيانات رحلة مغايرة للواقع **✅ الحل المقترح:** ```php // تضمين distance و duration في الـ price_token أيضاً if ($tokenData['distance'] != $distance || $tokenData['duration'] != $duration_text) { printFailure("Tampered ride data"); exit; } ``` --- ### [H-06] — Predictable Token Generation في `loginFirstTimeDriver.php` | المعلومة | التفصيل | |---------|---------| | **الفئة** | Weak Authentication | | **الخطورة** | 🟠 عالية | | **درجة CVSS** | 7.0/10 | | **CWE** | CWE-307, CWE-798 | | **الملف المتأثر** | `backend/loginFirstTimeDriver.php` | | **السطر المتأثر** | 40-48 | **📌 وصف الثغرة:** يتم استخدام كلمة مرور ثابتة `passwordnewpassenger` من متغيرات البيئة لكل السائقين الجدد. هذا يسمح لأي شخص يعرف هذه القيمة بتوليد توكن تسجيل صالح. **🔍 الكود الضعيف:** ```php $passwordnewpassenger = getenv('passwordnewpassenger'); if (!password_verify($password, $passwordnewpassenger)) { jsonError('Invalid credentials.', 401); } ``` **🎯 تأثير الاستغلال:** - إنشاء توكن تسجيل وهمي لأي سائق - بدء عملية تسجيل لحسابات متعددة - استنزاف موارد الـ OTP والإيميل **✅ الحل المقترح:** ```php // استخدام كلمة مرور فريدة لكل طلب تسجيل (One-Time Token) $registrationToken = bin2hex(random_bytes(32)); // تخزينها في Redis مع وقت صلاحية وربطها بمعرّف السائق $redis->setex("reg_token:{$id}", 600, $registrationToken); // التحقق من الـ token if (!hash_equals($redis->get("reg_token:{$id}"), $password)) { jsonError('Invalid registration token', 401); } ``` --- ## 🟡 الثغرات المتوسطة (Medium) --- ### [M-01] — ملفات Logs بصلاحيات 777 | المعلومة | التفصيل | |---------|---------| | **الفئة** | Security Misconfiguration | | **الخطورة** | 🟡 متوسطة | | **درجة CVSS** | 6.5/10 | | **CWE** | CWE-276 | | **الملف المتأثر** | `backend/core/helpers.php` | | **السطر المتأثر** | 158-159 | **📌 وصف الثغرة:** يتم إنشاء مجلد logs بصلاحيات 777 (قابلة للقراءة والكتابة والتنفيذ للجميع). هذا يسمح لأي مستخدم على السيرفر بقراءة وتعديل ملفات الـ logs. **🔍 الكود الضعيف:** ```php @mkdir($logDir, 0777, true); ``` **🎯 تأثير الاستغلال:** - قراءة معلومات حساسة من الـ logs (User IDs, Tokens, IPs) - تعديل الـ logs لإخفاء آثار الاختراق - حذف الـ logs **✅ الحل المقترح:** ```php @mkdir($logDir, 0750, true); // Owner: rwx, Group: rx, Others: --- ``` **📚 المراجع:** - CWE: https://cwe.mitre.org/data/definitions/276.html --- ### [M-02] — SQL Injection محتمل في `findBestDrivers` (Lady Case) | المعلومة | التفصيل | |---------|---------| | **الفئة** | SQL Injection (Potential) | | **الخطورة** | 🟡 متوسطة | | **درجة CVSS** | 6.0/10 | | **CWE** | CWE-89 | | **الملف المتأثر** | `backend/functions.php` | | **السطر المتأثر** | 113-114 | **📌 وصف الثغرة:** في حالة Lady، يتم إدراج `$femaleHash` مباشرة في الـ SQL. هذه القيمة مشفرة SHA-256 ولكنها لا تزال تُستخدم بدون Prepared Statement. **🔍 الكود الضعيف:** ```php case 'Lady': $femaleHash = 'bQ6yWJ2EVXKZooHdGclvmFiDlZCM8UYeO+ILFjDUvpQ='; $sql .= " AND cr.vehicle_category_id = $CAT_CAR AND d.gender = '$femaleHash' "; break; ``` **✅ الحل المقترح:** ```php case 'Lady': $femaleHash = 'bQ6yWJ2EVXKZooHdGclvmFiDlZCM8UYeO+ILFjDUvpQ='; $sql .= " AND cr.vehicle_category_id = ? AND d.gender = ? "; $params[] = $CAT_CAR; $params[] = $femaleHash; break; ``` --- ### [M-03] — عدم التحقق من SSL في cURL (Man-in-the-Middle) | المعلومة | التفصيل | |---------|---------| | **الفئة** | Insufficient Transport Layer Security | | **الخطورة** | 🟡 متوسطة | | **درجة CVSS** | 5.9/10 | | **CWE** | CWE-295 | | **الملف المتأثر** | `backend/functions.php` | | **السطر المتأثر** | 33-42, 51-61, 170-180, 193-210, 232-252, 342-354 | **📌 وصف الثغرة:** جميع استدعاءات cURL الداخلية إلى `http://188.68.36.205:2021` لا تستخدم SSL. هذا يسمح لأي شخص في نفس الشبكة باعتراض الاتصالات. **✅ الحل المقترح:** ```php // استخدام HTTPS بدلاً من HTTP $url = "https://188.68.36.205:2021"; // مع التحقق من SSL certificate curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); ``` --- ### [M-04] — عدم وجود فحص للـ Token Expiry في `loginJwtDriver.php` | المعلومة | التفصيل | |---------|---------| | **الفئة** | Business Logic | | **الخطورة** | 🟡 متوسطة | | **درجة CVSS** | 5.5/10 | | **CWE** | CWE-613 | | **الملف المتأثر** | `backend/loginJwtDriver.php` | | **السطر المتأثر** | 63-68 | **📌 وصف الثغرة:** عند فك تشفير `decPhone` و `decNat`، إذا فشلت عملية فك التشفير لا يتم تسجيل خطأ مناسب ولا يتم التحقق من وقت صلاحية بيانات الجلسة. **✅ الحل المقترح:** ```php if (empty($decPhone) || empty($decNat)) { securityLog("LoginDriver failed: decryption returned null", [ 'driver_id' => $driver['id'], 'phone_len' => strlen($driver['phone'] ?? 0), 'nat_len' => strlen($driver['national_number'] ?? 0) ]); unauthorizedDriver(); } ``` --- ## 🟢 الثغرات المنخفضة (Low) --- ### [L-01] — الـ Headers الأمنية غير كافية | المعلومة | التفصيل | |---------|---------| | **الفئة** | Security Misconfiguration | | **الخطورة** | 🟢 منخفضة | | **درجة CVSS** | 3.5/10 | | **CWE** | CWE-693 | | **الملف المتأثر** | `backend/core/bootstrap.php` | | **السطر المتأثر** | 29-36 | **📌 وصف الثغرة:** بعض الـ Security Headers الأساسية مفقودة أو غير كافية: - `Content-Security-Policy` غير موجود - `Referrer-Policy` غير موجود - `Permissions-Policy` غير موجود - `X-XSS-Protection` غير موجود (للمتصفحات القديمة) **✅ الحل المقترح:** ```php header("Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none'"); header("Referrer-Policy: strict-origin-when-cross-origin"); header("Permissions-Policy: geolocation=(), microphone=(), camera=()"); header("X-XSS-Protection: 1; mode=block"); ``` --- ### [L-02] — Email Header Injection في `helpers.php` | المعلومة | التفصيل | |---------|---------| | **الفئة** | Email Header Injection | | **الخطورة** | 🟢 منخفضة | | **درجة CVSS** | 3.1/10 | | **CWE** | CWE-93 | | **الملف المتأثر** | `backend/core/helpers.php` | | **السطر المتأثر** | 77-81 | **🔍 الكود الضعيف:** ```php function sendEmail(string $from, string $to, string $title, string $body): void { $header = "From: $from\nCC: $from"; mail($to, $title, $body, $header); } ``` **✅ الحل المقترح:** ```php function sendEmail(string $from, string $to, string $title, string $body): void { // تعقيم المدخلات لمنع injection $from = str_replace(["\r", "\n", "\r\n"], '', $from); $to = str_replace(["\r", "\n", "\r\n"], '', $to); $title = str_replace(["\r", "\n", "\r\n"], '', $title); $header = "From: $from\r\n"; $header .= "Reply-To: $from\r\n"; $header .= "MIME-Version: 1.0\r\n"; $header .= "Content-Type: text/html; charset=UTF-8\r\n"; mail($to, $title, $body, $header); } ``` --- ## 📊 جدول ملخص الثغرات | # | الثغرة | الملف | الخطورة | CVSS | |---|--------|-------|---------|------| | C-01 | SQL Injection في findBestDrivers | `functions.php:98-128` | 🔴 حرجة | 9.8 | | C-02 | Hardcoded Secrets Paths | `متعدد` | 🔴 حرجة | 9.3 | | C-03 | File Upload بدون Auth | `upload_audio.php` | 🔴 حرجة | 9.0 | | C-04 | Debug Mode مفعل | `bootstrap.php:11` | 🔴 حرجة | 8.6 | | C-05 | IV ثابت في AES-CBC | `encrypt_decrypt.php` | 🔴 حرجة | 8.0 | | H-01 | SSRF | `functions.php` | 🟠 عالية | 7.5 | | H-02 | HMAC Debug Disclosure | `JwtService.php:268` | 🟠 عالية | 7.5 | | H-03 | CORS Misconfiguration | `loginAdmin.php:9` | 🟠 عالية | 7.3 | | H-04 | Weak Encryption Flutter | `encrypt_decrypt.dart` | 🟠 عالية | 7.4 | | H-05 | Business Logic Pricing | `add_ride.php` | 🟠 عالية | 7.2 | | H-06 | Predictable Reg Token | `loginFirstTimeDriver.php` | 🟠 عالية | 7.0 | | M-01 | Logs Permissions 777 | `helpers.php:158` | 🟡 متوسطة | 6.5 | | M-02 | SQL Injection (Lady case) | `functions.php:114` | 🟡 متوسطة | 6.0 | | M-03 | No SSL Verification | `functions.php` | 🟡 متوسطة | 5.9 | | M-04 | No Token Expiry Check | `loginJwtDriver.php` | 🟡 متوسطة | 5.5 | | L-01 | Missing Security Headers | `bootstrap.php` | 🟢 منخفضة | 3.5 | | L-02 | Email Header Injection | `helpers.php:77` | 🟢 منخفضة | 3.1 | --- ## 🎯 خارطة طريق الإصلاح (Remediation Roadmap) ### المرحلة الأولى: فورية (خلال 24-48 ساعة) - [ ] **C-01**: إصلاح SQL Injection في `findBestDrivers` باستخدام Prepared Statements - [ ] **C-02**: نقل جميع المفاتيح إلى متغيرات البيئة فقط وإزالة الـ file_get_contents من الكود - [ ] **C-03**: إضافة JWT Authentication إلى `upload_audio.php` وتعقيم اسم الملف - [ ] **C-04**: تعطيل `display_errors` في الإنتاج ### المرحلة الثانية: قصيرة المدى (خلال أسبوع) - [ ] **C-05**: الترحيل الكامل إلى AES-256-GCM والتأكد من عدم استخدام IV ثابت - [ ] **H-01**: إضافة allowlist لعناوين URL في cURL - [ ] **H-02**: إزالة معلومات الـ Debug من استجابات الـ API - [ ] **H-03**: تقييد CORS للدومينات المسموحة فقط ### المرحلة الثالثة: متوسطة المدى (خلال شهر) - [ ] **H-04**: تحديث Flutter Encryption لاستخدام GCM مع IV عشوائي - [ ] **H-05**: تضمين جميع حقول الرحلة في الـ price_token - [ ] **H-06**: تطبيق One-Time Registration Tokens - [ ] **M-01**: تصحيح صلاحيات مجلد الـ logs ### المرحلة الرابعة: استراتيجية (شهر - 3 أشهر) - [ ] **M-02**: تحويل جميع استعلامات SQL إلى Prepared Statements - [ ] **M-03**: تفعيل SSL Verification في جميع اتصالات cURL - [ ] **M-04**: إضافة Logging مناسب لجميع حالات الفشل - [ ] **L-01 + L-02**: إضافة Security Headers وتأمين دالة الإيميل --- ## 🏆 نقاط القوة والنقاط الإيجابية على الرغم من النتيجة المنخفضة، هناك بعض الممارسات الجيدة في الكود: 1. ✅ **استخدام Prepared Statements** في معظم استعلامات SQL (عدا الـ findBestDrivers) 2. ✅ **وجود Rate Limiting** عبر Redis 3. ✅ **JWT مع JTI و Blacklist** لدعم إلغاء التوكنات 4. ✅ **استخدام `hash_equals`** لمقارنة آمنة (Timing Attack Safe) 5. ✅ **فصل قواعد البيانات** (Main, Ride, Tracking) لتقليل الضرر 6. ✅ **تطبيق فحص بصمة الجهاز (Fingerprint)** لمنع سرقة الجلسات 7. ✅ **استخدام `random_bytes`** لتوليد قيم عشوائية آمنة 8. ✅ **التحقق من MIME type الحقيقي** في رفع الصور عبر `finfo` --- ## 🔚 الخلاصة **درجة الأمان الإجمالية: 2.5/10** 🔴 النظام يحتوي على ثغرات حرجة تتطلب تدخلاً فورياً. الخطر الأكبر يكمن في: 1. إمكانية حقن SQL والوصول لقاعدة البيانات 2. وجود المفاتيح في مسارات معروفة داخل الكود 3. إمكانية رفع ملفات خبيثة بدون مصادقة 4. استخدام IV ثابت في التشفير **التوصية الفورية:** وقف أي deploy جديد حتى يتم إصلاح الثغرات الحرجة في المرحلة الأولى.