17 KiB
17 KiB
دليل الإصلاحات الشامل - مشروع سيرو
التاريخ: 16 يونيو 2026
المرحلة: التطبيق العملي للإصلاحات
الحالة: قيد التطوير
النقطة 1️⃣: مشكلة البصمة الضعيفة (Weak Fingerprint Authentication)
الملفات المتأثرة:
backend/login.php(الراكب)backend/loginJwtDriver.php(السائق)
المشكلة الحقيقية:
// ❌ الحالة الحالية في login.php
$fpVerified = hash_equals($storedFp, $fingerprint);
// ✅ يحمي من timing attacks فقط
// ⚠️ لكن البصمة نفسها ضعيفة وقابلة للاستخراج
لماذا ضعيفة؟
- البصمة مستخرجة من جهاز المستخدم (ANDROID_ID + IMEI + MAC + Build.MODEL)
- يمكن استخراجها عبر:
- Frida/Objection أثناء التطبيق
- ADB إذا كان USB debugging مفعل
- مفاتيح الجهاز المُخزنة
- بمجرد استخراج البصمة، يمكن تزويرها بنسخ نفس القيمة
الحل: تطبيق MFA (Multi-Factor Authentication)
المتطلبات:
عامل 1: بصمة الجهاز (الحالي) ✅
عامل 2: OTP عبر SMS ← أضف هذا
عامل 3: رمز الخادم (Server Token) ← أضف هذا
النقطة 2️⃣: مشكلة التشفير - IV الثابت
الملف المتأثر:
backend/encrypt_decrypt.php(الأساسي)
المشكلة الفعلية:
// ❌ المشكلة الحرجة جداً
$iv = getenv('initializationVector'); // 16 بايت ثابت!
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);
// ↑ نفس IV في كل مرة = نفس ciphertext لنفس plaintext!
return base64_encode($encrypted);
}
مثال عملي:
التشفير الأول: "+20123456789" → "abc123xyz=="
التشفير الثاني: "+20123456789" → "abc123xyz==" (متطابق!)
⚠️ هجوم معروف - يمكن كسر التشفير تماماً
الحل: توليد IV عشوائي
✅ الحل الصحيح:
public function encryptData($plainText) {
$plainText = mb_convert_encoding($plainText, 'UTF-8');
$paddedText = $this->addPadding($plainText);
// توليد IV عشوائي لكل تشفير
$randomIV = openssl_random_pseudo_bytes(16);
$encrypted = openssl_encrypt($paddedText, 'AES-256-CBC',
$this->key, OPENSSL_RAW_DATA, $randomIV);
// ضمّ IV مع النص المشفر
$result = $randomIV . $encrypted;
return base64_encode($result);
}
public function decryptData($encryptedData) {
$encrypted = base64_decode($encryptedData);
// استخرج IV من أول 16 بايت
$iv = substr($encrypted, 0, 16);
$ciphertext = substr($encrypted, 16);
$decrypted = openssl_decrypt($ciphertext, 'AES-256-CBC',
$this->key, OPENSSL_RAW_DATA, $iv);
return $this->removePadding($decrypted);
}
الخطوات:
- توليد 16 بايت عشوائية →
openssl_random_pseudo_bytes(16) - تشفير البيانات بـ IV العشوائي
- ضمّ IV + Ciphertext
- تحويل إلى base64
- عند فك التشفير: استخرج IV + Ciphertext وفك التشفير
النقطة 3️⃣: SQL Injection - الحالة الحالية وضح!
الملف المتأثر:
backend/functions.php(فيfindBestDrivers())
الحالة الحالية - ممتازة ✅
// ✅ هذا الكود **آمن تماماً** من SQL Injection
$carType = trim($carType);
$allowedCarTypes = [
'Comfort', 'Mishwar Vip', 'Scooter', 'Pink Bike',
'Electric', 'Lady', 'Van', 'Awfar Car', 'Fixed Price',
'Speed', 'Rayeh Gai'
];
// ✅ استخدام Allowlist (أفضل طريقة)
if (!in_array($carType, $allowedCarTypes, true)) {
$carType = 'Speed';
}
// ✅ معاملات SQL آمنة
$stmt = $con->prepare($sql);
$stmt->execute($allParams);
لماذا هذا آمن؟
- Allowlist: قائمة بيضاء للقيم المسموحة فقط
- Prepared Statements: معاملات آمنة
- Type Strict (
true): التحقق الدقيق (in_array(..., true))
المشاكل المتبقية:
نقاط أخرى قد تحتاج فحص:
/backend/auth/- هل تستخدم prepared statements؟/backend/ride/- هل جميع الاستعلامات آمنة؟/walletintaleq.intaleq.xyz/v2/main/- حرج! تحتاج فحص كامل
النقطة 4️⃣: نظام المحفظة - أهم نقطة 🔴
الملفات المتأثرة:
/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/
├── add.php ..................... 🔴 حرج - بلا مصادقة
├── transfer.php ............... ⚠️ عالي
├── update.php ................. ⚠️ عالي
├── addFromAdmin.php ........... 🔴 حرج - مفتاح API ثابت
├── get.php .................... ⚠️ عالي
├── getWalletByDriver.php ...... ⚠️ عالي
└── getDriverDetails.php ....... ⚠️ عالي
الفهم الحالي:
تطبيق السائق
↓
POST /add ← يضيف الأموال
↓
/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/add.php
↓
← لا يوجد مصادقة! ❌
الحل المقترح: (S2S - Server to Server)
تطبيق السائق
↓
POST /wallet/add (مع JWT توكن)
↓
BACKEND SERVER (backend/wallet/) ← نقطة جديدة
↓
• التحقق من JWT ✅
• فحص الملكية ✅
• التحقق من المبلغ ✅
↓
POST /v2/main/ride/driverWallet/add
(مع توقيع HMAC-SHA256)
↓
WalletIntaleq Server
↓
• التحقق من التوقيع ✅
• تنفيذ العملية ✅
• تسجيل دقيق ✅
الخطوات العملية:
1️⃣ إنشاء endpoint في Backend
// backend/wallet/add.php (جديد)
require_once __DIR__ . '/../core/bootstrap.php';
function requireAuth() {
$headers = getallheaders();
$authHeader = $headers['Authorization'] ?? '';
if (!preg_match('/Bearer\s+(\S+)/', $authHeader, $matches)) {
http_response_code(401);
jsonError('Authentication required');
}
$token = $matches[1];
$jwtService = new JwtService($redis);
try {
$decoded = $jwtService->verifyAccessToken($token);
return $decoded;
} catch (Exception $e) {
http_response_code(401);
jsonError('Invalid token');
}
}
try {
$user = requireAuth(); // JWT verification
// التحقق من الدور (التفويض)
if ($user->role !== 'driver') {
http_response_code(403);
jsonError('Permission denied');
}
$driverID = $user->id;
$amount = floatval(filterRequest('amount'));
$source = filterRequest('source');
// التحقق من المبلغ
if ($amount <= 0 || $amount > 10000) {
jsonError('Invalid amount (max 10,000)', 400);
}
// تحديد السرعة
$limiter = new RateLimiter($redis);
$limiter->enforce("wallet_add_{$driverID}", 'add', 1, 60); // 1 request per 60 seconds
// تسجيل التدقيق
$auditLog = "Driver {$driverID} requested to add {$amount} from {$source}";
securityLog($auditLog);
// الاتصال بـ WalletIntaleq عبر S2S
$walletResponse = callWalletAPI('add', [
'driver_id' => $driverID,
'amount' => $amount,
'source' => $source,
'backend_request' => true,
]);
if ($walletResponse['status'] === 'success') {
jsonSuccess(['message' => 'تمت إضافة الأموال بنجاح']);
} else {
jsonError('Wallet operation failed', 500);
}
} catch (Exception $e) {
securityLog("Wallet add error: " . $e->getMessage());
jsonError('Internal error', 500);
}
2️⃣ دالة S2S API call آمنة
// backend/core/WalletConnector.php (جديد)
class WalletConnector {
private $walletUrl = 'https://walletintaleq.intaleq.xyz/v2/main/';
private $hmacSecret = null;
public function __construct() {
$this->hmacSecret = getenv('WALLET_HMAC_SECRET');
if (!$this->hmacSecret) {
throw new Exception("WALLET_HMAC_SECRET not configured");
}
}
public function call($endpoint, $data) {
// إضافة timestamp لمنع Replay Attacks
$data['timestamp'] = time();
$data['nonce'] = bin2hex(random_bytes(16));
// فرز البيانات وإنشاء signature
ksort($data);
$payload = json_encode($data);
$signature = hash_hmac('sha256', $payload, $this->hmacSecret);
// إرسال الطلب
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $this->walletUrl . $endpoint,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'X-Signature: ' . $signature,
'X-Timestamp: ' . $data['timestamp'],
'X-Backend-ID: ' . getenv('BACKEND_ID'),
],
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_TIMEOUT => 10,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// التحقق من الاستجابة
$decoded = json_decode($response, true);
if ($httpCode !== 200 || $decoded['status'] !== 'success') {
throw new Exception("Wallet API error: " . $response);
}
return $decoded;
}
}
3️⃣ تعديل WalletIntaleq
// walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/add.php
<?php
// ✅ الآن يتلقى طلبات من Backend فقط
require_once __DIR__ . '/../../../core/bootstrap.php';
header('Content-Type: application/json');
try {
// الحصول على البيانات المرسلة
$payload = file_get_contents('php://input');
$data = json_decode($payload, true);
// التحقق من التوقيع (HMAC)
$signature = $_SERVER['HTTP_X_SIGNATURE'] ?? '';
$expectedSignature = hash_hmac('sha256', $payload, getenv('WALLET_HMAC_SECRET'));
if (!hash_equals($signature, $expectedSignature)) {
http_response_code(401);
jsonError('Invalid signature');
}
// التحقق من الـ Timestamp (Replay Attack Prevention)
$timestamp = $_SERVER['HTTP_X_TIMESTAMP'] ?? 0;
if (abs(time() - $timestamp) > 300) { // 5 دقائق
http_response_code(401);
jsonError('Request expired');
}
// الآن آمن - نفذ العملية
$driverID = $data['driver_id'];
$amount = $data['amount'];
$source = $data['source'];
// أضف إلى قاعدة البيانات
$stmt = $con->prepare(
"INSERT INTO driverWallet (driver_id, amount, source, created_at, updated_at)
VALUES (?, ?, ?, NOW(), NOW())"
);
$stmt->execute([$driverID, $amount, $source]);
// تسجيل التدقيق
securityLog("Wallet added: Driver $driverID, Amount $amount from $source");
jsonSuccess(['message' => 'Added successfully']);
} catch (Exception $e) {
securityLog("Wallet error: " . $e->getMessage());
jsonError('Internal error', 500);
}
?>
النقطة 5️⃣: أمان تطبيقات الهاتف - الأذونات
الملف المتأثر:
siro_driver/android/app/src/main/AndroidManifest.xml
الأذونات الحالية:
<!-- ✅ ضرورية لتطبيق السائق -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<!-- ⚠️ تحتاج فحص -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!-- ✅ ضرورية للاتصالات -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
الفحص المطلوب:
1. بحث في codebase تطبيق السائق:
grep -r "getExternalFilesDir\|getExternalCacheDir\|Environment.getExternalStorageDirectory" .
إذا لم تظهر نتائج → احذف WRITE/READ_EXTERNAL_STORAGE
2. بحث عن SYSTEM_ALERT_WINDOW:
grep -r "TYPE_APPLICATION_OVERLAY\|canDrawOverlays" .
إذا لم تظهر → احذفها
3. بحث عن MODIFY_AUDIO_SETTINGS:
grep -r "setVolume\|adjustStreamVolume" .
إذا لم تظهر → احذفها
النقطة 6️⃣: load_env.php - تحميل آمن للمتغيرات
الملف:
backend/load_env.php
الحالة الحالية:
<?php
function loadEnvironment($env_file) {
if (!file_exists($env_file)) {
error_log("❌ .env not found: $env_file");
return false;
}
$lines = file($env_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
$line = trim($line);
if (empty($line) || strpos($line, '#') === 0) continue;
$parts = explode('=', $line, 2);
if (count($parts) === 2) {
[$keyName, $value] = $parts;
$value = trim($value, "\"'");
putenv("$keyName=$value");
$_ENV[$keyName] = $value;
$_SERVER[$keyName] = $value;
}
}
return true;
}
القوة الأمنية:
✅ جيد جداً:
- يتحقق من وجود الملف
- يتجاهل التعليقات (#)
- يتجاهل الأسطر الفارغة
- يزيل علامات الاقتباس
- يحمل في
$_ENVو$_SERVER
الطريقة الموصى بها (Composer autoload):
// composer.json - الأفضل
"autoload": {
"files": ["src/bootstrap.php"]
}
// src/bootstrap.php
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
النقطة 7️⃣: backend/functions.php - الروابط الآمنة
الحالة الحالية:
❌ غير آمنة:
$url = "http://188.68.36.205:2021";
$url = "http://188.68.36.205:3031";
$url = "https://location.intaleq.xyz";
المشاكل:
- IP عام مكشوف - 188.68.36.205
- HTTP بدل HTTPS - عرضة لـ MITM attacks
- لا يوجد certificate pinning
الحل:
// ✅ الحل الآمن
function getAllowedSocketUrls(): array {
return [
'https://location.siromove.com', // ✅ HTTPS + Domain
'https://socket.siromove.com', // ✅ HTTPS + Domain
// لا HTTP
];
}
function sendToLocationServer($action, $data) {
$url = "https://location.siromove.com/api";
// تثبيت الشهادة (Certificate Pinning)
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => http_build_query($data),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
// ✅ تأمين SSL/TLS
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_CAINFO => '/etc/ssl/certs/ca-bundle.crt',
// ✅ Certificate Pinning (اختياري لكن موصى)
// تحتاج حساب SHA-256 للشهادة
CURLOPT_PINNEDPUBLICKEY => 'sha256/AAAA....',
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
ملخص الإصلاحات
| النقطة | المشكلة | الحل | المدة |
|---|---|---|---|
| 1 | بصمة ضعيفة | MFA + OTP | 8 ساعات |
| 2 | IV ثابت | توليد عشوائي | 4 ساعات |
| 3 | SQL Injection | آمن بالفعل ✅ | 0 ساعات |
| 4 | المحفظة بلا مصادقة | S2S + JWT | 16 ساعات |
| 5 | أذونات مفرطة | تقليص + فحص | 4 ساعات |
| 6 | load_env.php | آمن بالفعل ✅ | 0 ساعات |
| 7 | روابط HTTP | تبديل HTTPS | 2 ساعات |
المجموع: ~34 ساعة
التالي:
- تطبيق الإصلاحات واحدة تلو الأخرى
- اختبار كل إصلاح
- ترحيل قاعدة البيانات
- نشر للإنتاج