IDOR و Policies لارافيل
الثغرة رقم 1 في العالم مش ذكية، هي تشيك اتنسى. الدرس ده هيخليك تخترق متجر بإيدك بتغيير رقم في الـ URL، وتصعّد نفسك لأدمن بحقل زيادة في form، وبعدين تقفل الاتنين بطبقات فوق بعض في لارافيل.
- تعرف Broken Access Control وأشكاله الأربعة، والفرق بين Horizontal و Vertical
- تخترق وتصلّح IDOR، وتعرف إمتى ترجّع 403 وإمتى 404
- تفهم ليه الـ UUID مش حماية
- تستخدم Gates و Policies والـ middleware والـ queries المتحددة كطبقات
1. Broken Access Control
في قايمة OWASP Top 10 (أشهر قايمة لثغرات الويب) سنة 2021، الثغرة دي طلعت المركز الأول، بعد ما كانت الخامسة. ومش عشان صعبة. عشان سهلة جداً تتنسي.
نوعين من التصعيد (Privilege Escalation)
| النوع | معناه | مثال في المتجر |
|---|---|---|
| Horizontal (أفقي) | توصل لداتا مستخدم تاني في نفس مستواك | عميل يشوف أوردر وعنوان عميل تاني |
| Vertical (رأسي) | تاخد صلاحيات مستوى أعلى منك | عميل يغيّر سعر منتج أو يبقى أدمن |
4 أشكال هتقابلها
| الشكل | إزاي | الحماية |
|---|---|---|
| IDOR | تغيّر رقم في الـ URL وتشوف حاجة حد تاني | سكشن 2 كله |
| Mass Assignment | صفحة “تعديل البروفايل” بتعمل $user->update($request->all()). الهاكر يضيف في الـ request حقل is_admin=1، فيبقى أدمن |
$fillable في الـ model، وإنك تستخدم $request->validated() بدل all() |
| Forced Browsing | صفحة /admin/reports مش ظاهرة في المنيو، بس مفيش عليها middleware. أي حد يكتب العنوان يدخل |
كل routes الأدمن جوه group واحد عليه الحماية |
| API أضعف من الـ UI | الـ Blade فيه @can، بس الـ API endpoint اللي بيعمل نفس العملية مفيهوش تشيك |
التشيك يبقى في Policy واحدة، والـ web والـ API الاتنين ينادوها |
جرّب الـ Mass Assignment بنفسك: احفظ عادي، وبعدين افتح “DevTools” وزوّد الحقل:
Broken Access Control مش ثغرة ذكية. هي تشيك اتنسى. وعشان كده لازم التشيك يبقى في مكان واحد ميتنسيش.
2. IDOR (Insecure Direct Object Reference)
إنت عميل في shop-lab، وفتحت صفحة أوردرك: /orders/1043. فضولك خلاك تغيّر الرقم لـ 1042. لو الكود بيعمل Order::find($id) وخلاص، هتشوف أوردر واحد تاني: اسمه، وعنوانه، وتليفونه، واشترى إيه. وبسكريبت صغير، تسحب كل أوردرات المتجر.
جرّب بنفسك. ابدأ بالكود اللي فيه الثغرة، وغيّر الرقم، وبعدين شغّل سكريبت الهاكر. وبعدين بدّل لشكلين الكود التانيين:
403 ولا 404؟
لو جرّبت الاختيارين التاني والتالت، هتلاحظ إن الأول بيقول 403 والتاني بيقول 404. الاتنين بيمنعوك، بس الـ 403 بيأكدلك إن “الأوردر 1042 موجود، وهو مش بتاعك”. ده بيدّي الهاكر معلومة: يعرف عدد الأوردرات، ومعدل البيع في اليوم.
عشان كده، في الحاجات اللي المفروض المستخدم ميعرفش بوجودها أصلاً، رجّع 404. وفي لارافيل فيه Response::denyAsNotFound() عشان تعمل كده من جوه الـ Policy.
طب لو استخدمت UUID بدل الأرقام؟
الـ UUID زي 9b1d…e7a2 بيصعّب التخمين، وده كويس كطبقة زيادة، وبيخفي عدد الأوردرات. لكن مش حماية. الـ UUID بيتسرب في الإيميلات، والـ logs، ولينكات المشاركة، و screenshots. ولو التشيك مش موجود، أول ما UUID يتسرب الثغرة ترجع.
أي ID جاي من المستخدم معناه “عايز ده”، مش “ده بتاعي”. اتشيك على الملكية في كل مرة، والأحسن تجيبه من خلال المستخدم نفسه.
3. Authorization في لارافيل (Gates و Policies)
| Gate | Policy | |
|---|---|---|
| مربوطة بإيه | عملية عامة | Model معين |
| مثال | “يقدر يفتح لوحة الأدمن؟”، “يقدر يشوف التقارير؟” | OrderPolicy: view و cancel و refund |
| مكانها | AppServiceProvider |
app/Policies، ولارافيل بيلاقيها لوحده بالاسم |
أماكن التشيك (طبقات فوق بعض)
| الطبقة | إزاي | بتحمي من |
|---|---|---|
| Route Middleware | group لـ /admin عليه تشيك الأدمن، أو can: middleware |
Forced Browsing، والـ routes المنسية |
| Controller | $this->authorize('refund', $order) أو Gate::authorize |
القرار على الحاجة نفسها |
| Query | تجيب من علاقة المستخدم، أو Global Scope | IDOR حتى لو نسيت الـ Policy |
| Blade | @can عشان تخبي الزرار |
ده UX بس، مش حماية |
اختار هجوم وابعته. هتلاقي كل هجوم بتوقفه طبقة مختلفة. اطفي الطبقة اللي وقفته وابعت تاني:
تفاصيل بتفرق
before()في الـ Policy: بيتنادى قبل أي قاعدة. لو رجّعtrueللـ super admin، كل حاجة تبقى مسموحة. لو رجّعnull، القرار يكمل عادي. خلي بالك:falseمعناها منع، مش “مش عارف”.- الزوار: لو الـ method في الـ Policy مستنية
User $user، الزائر بيترفض أوتوماتيك. ولو عايز تسمحله (زي “أي حد يشوف المنتج”)، خلي النوع?User. - رسايل واضحة:
Response::deny('الأوردر اتشحن خلاص ومينفعش يتلغي')أحسن من 403 فاضية. - مكتبة Spatie laravel-permission: لو محتاج أدوار وصلاحيات متخزنة في الداتابيز والأدمن يغيّرها من لوحة. لكن ابدأ بإيدك الأول عشان تفهم.
الـ Gate للعمليات العامة والـ Policy لكل model، والحماية الحقيقية بتيجي من إن الطبقات فوق بعض، مش من طبقة واحدة.
أسئلة الإنترفيو
فكّر في إجابتك الأول، وبعدين افتح السؤال.
01يعني إيه IDOR، وإزاي تمنعه؟
إن السيرفر يجيب حاجة بالـ ID اللي المستخدم بعته من غير ما يتأكد إنها بتاعته، فيغيّر الرقم في الـ URL ويشوف داتا غيره. المنع: أجيب الحاجة من علاقة المستخدم نفسه، أو Policy بتتشيك على الملكية في كل request. والـ UUIDs بتصعّب التخمين بس مش حماية.
02ترجّع 403 ولا 404 لما حد يطلب حاجة مش بتاعته؟
403 بتأكد إن الحاجة موجودة، وده بيسرّب معلومة. لو المستخدم المفروض ميعرفش بوجودها، أرجّع 404. ولو هو عارف إنها موجودة وبس مش مسموحله بالعملية (زي إلغاء أوردر اتشحن)، 403 برسالة واضحة.
03Horizontal و Vertical Privilege Escalation؟
Horizontal إنك توصل لداتا مستخدم تاني في نفس مستواك، زي IDOR. Vertical إنك تاخد صلاحيات أعلى، زي عميل يبقى أدمن بالـ mass assignment أو بيدخل route أدمن مش محمي.
04الفرق بين Gate و Policy في لارافيل؟
الـ Gate قاعدة لعملية عامة مش مربوطة بـ model، زي "يفتح لوحة التقارير". الـ Policy كلاس بيجمع كل قواعد model واحد، زي OrderPolicy فيها view و cancel و refund. والـ before() في الـ Policy بتتنادى الأول، و true فيها بتسمح بكل حاجة.
05إيه هو Mass Assignment وإزاي بيوصّل لتصعيد صلاحيات؟
لما تعمل update بكل اللي جه في الـ request، الهاكر يضيف حقل زي is_admin=1 ويبقى أدمن. الحماية $fillable في الـ model، واستخدام validated() بدل all().
06الـ UUID بدل الـ auto-increment بيحل IDOR؟
لأ. بيصعّب التخمين وبيخفي عدد الصفوف، وده كويس كطبقة زيادة. بس الـ UUIDs بتتسرب في الإيميلات والـ logs ولينكات المشاركة، ومن غير تشيك ملكية الثغرة لسه موجودة.