سجلّ قابل للمعالجة لكل ما رُصد في كود سيرو الحيّ أثناء بناء Tripz: IDOR السحب · double-spend · تسرّب رسم 3500 · 5 كتابات بلا معاملة · مقارنة كلمة مرور نصّية تتجاوز الـhash · كلمة مرور مشتركة ثابتة · OTP 3 خانات · مسح جدول وفكّ تشفير للتحقق · AES-CBC بـIV ثابت · إلخ. كل بند بخطورته وإصلاحه المقترح لسيرو وكيف عالجناه في Tripz. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
7.5 KiB
7.5 KiB
21 — تدقيق سيرو: العيوب الأمنية والمشاكل المرصودة
سجلّ قابل للمعالجة لكل ما رُصد في كود سيرو الحيّ (
~/development/App/Siro) أثناء بنائنا لـTripz. الغرض مزدوج: (1) ألّا نكرّرها في Tripz، (2) قائمة إصلاحات جاهزة لسيرو نفسه حين نعالجه.كل ما يلي في سيرو (PHP/MySQL) لا في Tripz. حيث أصلحنا المكافئ في Tripz، أُشير إليه. الخطورة: 🔴 حرجة · 🟠 متوسطة · 🟡 منخفضة/جودة.
آخر تحديث: 2026-07-17.
المدفوعات والسحب (payment_server/ · request_payout.php · finalizePayout)
| # | الخطورة | العيب | الإصلاح المقترح لسيرو | حالنا في Tripz |
|---|---|---|---|---|
| S1 | 🔴 | IDOR في السحب: request_payout.php يأخذ driverId/phone من جسم الطلب لا من التوكن — سائق يسحب رصيد غيره إلى هاتفه. |
اشتقاق هوية السائق من JWT الموقَّع حصراً. | ✅ نظيف — payouts.request يستعمل user.userId من التوكن. |
| S2 | 🔴 | لا حجز رصيد عند طلب السحب → طلبات متزامنة تمرّ كلها = double-spend. | حجز ذرّي عند التأكيد قبل أي تحويل. | ✅ خصم ذرّي عند confirm (I1/I4). |
| S3 | 🔴 | رسم 3500 يناقض نفسه: الفحص يتطلب amount + 3500 والإنهاء يخصم amount - 3500 = تسرّب مال. الرقم مكتوب يدوياً مرّتين. |
ثابت واحد + اختبار يطابق الفحص بالخصم. | ✅ لا رسم مكرّر؛ العمولة من الرصيد التشغيلي (docs/18). |
| S4 | 🔴 | finalizePayout يعمل 5 كتابات بلا معاملة/تراجع → فشل في المنتصف يترك سحباً نصف مُسوّى. |
لفّ الكتابات في transaction واحدة. | ✅ الخصم والقيد في معاملة واحدة (I1). |
| S5 | 🟠 | driverWallet.amount نوعه varchar(10) — المال مخزَّن نصّاً، وSUM() على نصوص. |
تحويله DECIMAL(12,3). |
✅ numeric(12,3) + CHECK (balance >= 0). |
| S6 | 🟠 | لا OTP على السحب — phone_verification موجود لكنه مربوط بالتسجيل/الدخول فقط. |
OTP + تحقّق قبل التحويل. | ✅ OTP على السحب عبر المُوزِّع (I4). |
| S7 | 🟡 | جدولان متداخلان لنفس المفهوم: payout_requests وdriver_withdrawal_requests. |
توحيدهما في جدول واحد. | ✅ جدول pay_payouts واحد. |
المصادقة وكلمة المرور (auth/)
| # | الخطورة | العيب | الإصلاح المقترح لسيرو | حالنا في Tripz |
|---|---|---|---|---|
| S8 | 🔴 | مقارنة كلمة مرور نصّية: loginUsingCredentialsWithoutGoogle.php سطر 114 — `password_verify(...) |
$password === $data['password']`. الشقّ الثاني يتجاوز الـhash كلياً، ويطابق كلمة المرور المخزَّنة نصّاً لو كانت كذلك. | |
| S9 | 🟠 | كلمة مرور مشتركة ثابتة 'SiroPassenger2026!' للحسابات التجريبية في الكود. |
نقلها لمتغيّر بيئة على الأقل، والأفضل إزالة المسار. | ✅ لا مسار كلمة مرور. |
| S10 | 🟡 | password = hash($email) وهمي عند التسجيل — حقل بلا معنى يوحي بأمان غير موجود. |
إزالة العمود إن لم يُستعمل. | ✅ لا عمود كلمة مرور. |
| S11 | 🟠 | user_type يُؤخذ من الطلب بلا تحقّق توقيع (تعليقهم صريح: "JWT not trusted without signature verification") — عميل يدّعي admin. يُلطَّف جزئياً بقائمة ADMIN_PHONE_NUMBERS. |
التحقق من توقيع JWT واعتماد الدور منه. | ✅ الدور من التوكن الموقَّع (RolesGuard). |
الـOTP (auth/otp/)
| # | الخطورة | العيب | الإصلاح المقترح لسيرو | حالنا في Tripz |
|---|---|---|---|---|
| S12 | 🟠 | رمز OTP من 3 خانات (1000 احتمال فقط) — قابل للتخمين. | 6 خانات + قفل بعد المحاولات. | ✅ 4 خانات (قابل للرفع) + قفل 5 محاولات (D4). عند النقل نرفعه لـ6. |
| S13 | 🟠 | مسح جدول كامل وفكّ تشفير كل صف للتحقق من الرمز (verify.php: SELECT * ... foreach decrypt) — بطيء ويتسرّب توقيتاً. |
فهرس أعمى (blind index) على الهاتف. | ✅ phone_bidx (HMAC حتمي) للبحث المباشر (docs/16). |
| S14 | 🟡 | مساران متوازيان للـOTP: request.php/verify.php (قاعدة، مشفّر) وOtpService.php (Redis) — تكرار وتضارب. |
توحيد على مسار واحد. | ✅ مسار Redis واحد. |
| S15 | 🟡 | echo لأخطاء المزوّد الخام في sendIntaleqOtp ("Temporarily echo the raw error") — تسريب تشخيصي في الإنتاج. |
إزالة الـecho، لوغ فقط. | ✅ لا echo؛ لوغ خادمي. |
| S16 | 🟡 | تخزين OTP مشفَّراً بـGCM في القاعدة ثم مسح الجدول لفكّه — تكلفة بلا فائدة (الرمز قصير العمر، الأنسب Redis + hash). | Redis + password_hash كما في OtpService. |
✅ Redis مباشرةً. |
التشفير (core/Security/EncryptionHelper.php)
| # | الخطورة | العيب | الإصلاح المقترح لسيرو | حالنا في Tripz |
|---|---|---|---|---|
| S17 | 🔴 | AES-CBC بـIV ثابت (موثَّق سابقاً في docs/16) — نفس النص ينتج نفس الشيفرة، ويسرّب الأنماط. | AES-256-GCM + IV عشوائي لكل قيمة. | ✅ منفَّذ (docs/16). |
حدّ الطلبات (core/Auth/RateLimiter.php) — جيد، للنسخ لا للإصلاح
تصميمه سليم: حدود مسمّاة لكل نوع + fallback بملف عند تعطّل Redis (fail-closed). النقطة الوحيدة: يتتبّع بـIP:userId — جيد، لكن نقاط ما قبل الدخول بالـIP وحده (لا مفرّ). ليس عيباً — مرجع نتعلّم منه.
نقاط تحتاج تأكيد المالك (لم أجزم بها)
- هل
raw_sms_log+ Gemini (تسوية الدفع من رسائل المزوّد) يُدقَّق ضد إعادة الاستعمال (نفس الرسالة تُسوّى مرتين)؟ — يحتاج فحصwebhook_sms/webhook.phpعند معالجة سيرو. - هل توكنات Nabeh/مفاتيح Kazumi في متغيّرات بيئة على كل الخوادم أم مكتوبة في مكان ما؟ — يُتحقَّق عند النقل.
← ذو صلة: 16-encryption · 17-backend-backlog · 18-driver-credit-commission