# ثغرات تسجيل الدخول برقم الموبايل (كود الواتساب) — تقرير فحص

> **الحالة: موثّق بس، ما انصلح شي.** هاد تقرير لتاسك منفصل جاي.
> تاريخ الفحص: 5 تشرين الأول 2026. الفحص قراءة بس، على الكود، والأرقام مأخوذة من نسخة محلية من قاعدة اللايف.
> **ملف حساس:** فيه وصف لثغرات موجودة هلق على اللايف. ممنوع مشاركته برا الفريق.

## الخلاصة بسطرين
- الدخول بالموقع وبالتطبيق بيمشي هيك: رقم موبايل، بعدين **كود من 4 أرقام** بيوصل على الواتساب. هالكود **ما إلو مدة صلاحية، وما في حد لعدد المحاولات، وما في حد لعدد مرات الإرسال**.
- النتيجة: حدا بيقدر **يفوت على حساب أي زبون إذا بيعرف رقمه بس**، أو يكلّفنا آلاف رسائل الواتساب، أو يعمل حساب برقم مو إلو.

## الأولويات (شو منصلّح أول)
| الأولوية | الثغرة | ليش |
|---|---|---|
| 🔴 فوراً | #1 تخمين الكود | الدخول على حساب أي زبون |
| 🔴 فوراً | #2 رابط التجربة المفتوح | أي حدا بيبعت واتساب على حسابنا وباسمنا |
| 🔴 فوراً | #3 ما في حد للإرسال | كلفة مفتوحة، وإزعاج للناس |
| 🟠 قريباً | #4 التسجيل بدون كود | حسابات برقم شخص تاني |
| 🟠 قريباً | #5 الكود ما بيخلص | بيزيد خطر #1 |
| 🟡 بعدين | #6 إلى #9 | أقل خطراً |

**الخبر المنيح:** في كلاس جاهز ومكتوب منيح للكودات اسمه `app/Services/OtpService.php`، وعليه مدة صلاحية وحد للإرسال، بس **ما حدا عم يستعمله**. الأسهل إنو نخلي كل أماكن الدخول تستعمله بدل ما نكتب شي جديد.

---

## 🔴 1. تخمين الكود والدخول على حساب أي زبون
- **شو المشكلة:** الكود 4 أرقام، يعني 10,000 احتمال بس. وما في شي بيوقف حدا عن تجربة كود ورا كود.
  - **بالموقع:** ما في أي حد لعدد المحاولات أبداً.
  - **بالتطبيق:** الحد 600 طلب بالدقيقة لكل IP، يعني الـ 10,000 احتمال بيخلصوا بحوالي ربع ساعة من جهاز واحد، وأسرع إذا من أكتر من جهاز.
- **شو بيصير:** واحد بيعرف رقم زبون، بيطلب كود لرقمه (بيوصل الكود للزبون الحقيقي)، وبعدين بيجرّب الاحتمالات لحد ما يزبط معه **ويفوت على الحساب**: بيشوف طلباته وعناوينه ورقمه، وبيقدر يطلب باسمه.
- **وين بالكود:**
  - الموقع: `HomeController::verifyOtpAndLogin` (سطر 1120)، والراوت `POST /dashboard/login/otp/verify` (`routes/web.php:391`).
  - التطبيق: `Api/V2/AuthController::verifyOtp` (سطر 453)، والراوت `POST /api/v2/verify-otp`.
  - الـ checkout: `CheckoutController::verifyPhone` (سطر 216).
  - التاجر: `HomeController::verifyOtpAndLoginSeller` (سطر 803)، وهو نفس المشكلة على حسابات التجار.
  - حد الـ API: `RouteServiceProvider.php:391` (600 بالدقيقة).
- **الحل:**
  - بعد **5 محاولات غلط** الكود بيبطل، والزبون لازم يطلب كود جديد.
  - حد محاولات لكل رقم ولكل IP، مثلاً 10 بالساعة.
  - `OtpService` فيه هالشغلات جاهزة.

## 🔴 2. رابط تجربة منسي بيبعت واتساب لأي رقم
- **شو المشكلة:** الرابط `GET /test/whatsapp-otp?phone=...&code=...` مفتوح لأي حدا بالعالم، بدون تسجيل دخول.
  - بيخلي سيرفرنا يبعت **رسالة واتساب "كود تحقق" لأي رقم، وبالكود يلي بيختاره المرسل**.
  - في رابط تاني جنبه `POST /otp/whatsapp/send` بيعمل نفس الشي (بس بيحتاج توكن CSRF، وهاد سهل ياخده أي حدا من الموقع).
- **شو بيصير:**
  - أي حدا بيقدر يبعت آلاف الرسائل **على حسابنا**.
  - بيقدر يبعت لناس رسائل "كود تحقق" مزيّفة **باسم كابيتانو**، وهاد ممكن يستعمل للاحتيال.
- **وين بالكود:** `routes/web.php:128` و`routes/web.php:132`، والكلاس `IshaarOtpController`.
- **الحل:** **نحذف الرابطين.** ما في شي بالموقع ولا بالتطبيق بيستعملهن.

## 🔴 3. ما في حد لعدد مرات إرسال الكود
- **شو المشكلة:** أي حدا بيقدر يطلب كود لنفس الرقم، أو لأرقام مختلفة، بدون أي حد. وكل رسالة واتساب إلها كلفة.
  - **بالموقع:** ما في حد أبداً.
  - **بالتطبيق:** 600 بالدقيقة. وملف مبرمج التطبيق بيقول إنو التطبيق **ما بيحط أي مهلة** على زر "إعادة الإرسال"، يعني الحماية لازم تكون من السيرفر.
- **شو بيصير:** فاتورة واتساب مفتوحة، وإزعاج لزباين حقيقيين بيوصلهم رسائل ما طلبوها.
- **وين بالكود:**
  - `HomeController::sendOtpForLogin` (سطر 674)، و`sendOtpForLogin2` (سطر 901، إعادة الإرسال).
  - `sendOtpForSellerLogin` (سطر 725).
  - `Api/V2/AuthController::sendOtp` (سطر 376).
  - `CheckoutController::checkPhone` (سطر 132).
- **الحل:**
  - رسالة وحدة بالدقيقة لكل رقم، و5 بالساعة.
  - حد لكل IP كمان.
  - إذا تجاوز الحد، رسالة واضحة متل "حاول بعد دقيقة". التطبيق جاهز لهيك رد: `{ "result": false, "message": "..." }`.

## 🟠 4. بيقدر حدا يعمل حساب برقم شخص تاني بدون كود
- **شو المشكلة:** طلب التسجيل (`POST /dashboard/register` بالموقع، و`POST /api/v2/auth/register` بالتطبيق) **ما بيتأكد إنو الرقم انتحقق منه بكود قبل**. بس بيتأكد إنو الرقم مو مسجّل من قبل.
- **شو بيصير:**
  - حدا بيعمل حساب برقم مو إلو، فصاحب الرقم الحقيقي بيلاقي إنو "رقمه مستعمل".
  - أو بيعمل حسابات وهمية بكثرة.
  - ملف مبرمج التطبيق بيطلب هالإصلاح صراحة (القسم 5.4).
- **وين بالكود:** `HomeController::register` (سطر 1255)، و`registerSeller` (سطر 957)، و`Api/V2/AuthController::register` (سطر 184).
- **الحل:**
  - لما الكود يزبط لرقم جديد، منسجّل بالسيرفر إنو "هالرقم انتحقق منه للتو" لمدة قصيرة (مثلاً 15 دقيقة).
  - التسجيل بيقبل **بس هالرقم بالذات**، وبيرفض أي رقم غيره برسالة واضحة.
  - (في شي شبيه موجود للحسابات المحذوفة: `AccountDeactivationUtility::rememberVerifiedPhone`).

## 🟠 5. الكود ما إلو مدة صلاحية
- **شو المشكلة:** الكود بينحفظ بجدول `temp_auth`، وبيضل صالح لحد ما ينستعمل أو ينطلب كود جديد. كود عمره أسبوع بيضل شغّال. وبالكود في سطر معلّق مكتوب فيه "Optional expiration".
- **شو بيصير:** بيزيد خطر الثغرة #1، لأنو المهاجم بياخد كل الوقت يلي بدو ياه ليخمّن.
- **وين بالكود:** `Api/V2/AuthController.php:488` (السطر المعلّق)، و`verifyOtpAndLogin`، و`verifyPhone`.
- **الحل:** صلاحية **5 دقائق** من وقت الإرسال (الجدول فيه `updated_at` أصلاً)، والكود الجديد بيلغي القديم.

## 🟡 6. الكود بينولّد بطريقة عشوائية ضعيفة
- **شو المشكلة:** `rand()` مو آمن للأمور الأمنية، لأنو ممكن نوعاً ما يتوقّع الرقم الجاي. المكان الوحيد يلي معمول صح هو الـ checkout (`random_int`).
- **وين بالكود:** `HomeController` (السطور 694 و742 و922)، و`Api/V2/AuthController` (سطر 395).
- **الحل:** `random_int(0, 9999)` بكل الأماكن. تعديل سطر واحد بكل مكان.

## 🟡 7. معرفة إذا الرقم إلو حساب
- **شو المشكلة:** فحص الرقم بالـ checkout (`/checkout/check-phone`) بيرجّع إذا الرقم مسجّل أو لا. وكمان `guest-customer-info-check` بالتطبيق. يعني حدا بيقدر يجرّب أرقام ويعرف مين زبون عندنا.
- **الخطورة:** قليلة لحالها، بس بتسهّل الثغرة #1 لأنو المهاجم بيعرف أي أرقام إلها حسابات.
- **الحل:** حد لعدد الفحوصات لكل IP. والأفضل إنو الجواب يكون نفسه للرقمين، والفرق يبين بس بعد الكود الصحيح متل ما بيعمل التطبيق.

## 🟡 8. أرقام محفوظة بصيغة قديمة غلط
- **شو المشكلة:** **185 زبون** رقمهم مو بصيغة `+963...` الموحّدة. الدخول بيدوّر على الرقم بالضبط، فهدول ما بيلاقيهم.
- **شو بيصير:**
  - الزبون بيطلب كود، وبيروح على "تسجيل جديد" مع إنو عنده حساب.
  - فبيطلعله "رقمك مستعمل"، أو بينعمل إلو حساب تاني.
- **الحل:** سكريبت لمرة وحدة بيوحّد صيغة الأرقام. بس **أول شي** لازم نشوف إذا في رقمين رح يصيروا نفس الرقم بعد التوحيد، لأنو هي حسابات مكرّرة بدها قرار.

## 🟡 9. رسائل خطأ ممكن توقّع شاشة التطبيق
- **شو المشكلة:** بـ `verify-otp`، إذا الرقم أو الكود انبعت بصيغة غلط، السيرفر بيرجّع `message` **كقائمة**. وملف مبرمج التطبيق بيقول إنو هاد **بيوقّع الشاشة** (لازم يكون نص).
- **وين بالكود:** `Api/V2/AuthController.php:462-467`.
- **الحل:** نرجّع أول رسالة كنص.

---

## شو ما لقيت فيه مشكلة
- **الكود بينستعمل مرة وحدة** وبينحذف بعدها، بكل الأماكن.
- **الحساب المحظور** ما بيقدر يفوت.
- **الحسابات المحذوفة** بترجع بنفس الحساب بعد الكود، وما في شي بينكسر.
- **مشكلة "الإيميل مو متحقق منه"** يلي ذكرها ملف التطبيق: ما في ولا زبون متأثر هلق (0 من 6366).

## ملاحظة للتاسك
الثغرات #1 و#3 و#5 و#6 بتتصلّح كلها مع بعض إذا خلّينا كل أماكن الدخول تستعمل **`OtpService` الموجود**: صفحة الدخول، والتطبيق، والـ checkout، والتاجر. وهيك منوحّد الكود بمكان واحد بدل خمس نسخ.

**لازم تنجرّب مع التطبيق قبل الرفع:** الردود لازم تضل متل ما بيتوقعها التطبيق (الملف `LOGIN_BACKEND_WORKFLOW.md` من مبرمج التطبيق).
