السلام عليكم أعضاء المنتدى،
أحب أن أطرح موضوعًا عن واحدة من أكثر الثغرات شيوعًا وخطورة في تطبيقات الويب وواجهات API، وهي IDOR أو ما يعرف في OWASP API Security Top 10 باسم BOLA – Broken Object Level Authorization.
التصنيفات المرتبطة:
OWASP API Security Top 10 2023 – API1: Broken Object Level Authorization
CWE-639: Authorization Bypass Through User-Controlled Key
الفكرة باختصار: التطبيق يتحقق من أن المستخدم مسجل دخول، لكنه لا يتحقق من أن المستخدم يملك أو يصرح له بالوصول إلى الكائن المطلوب.
ما هي الثغرة؟
تحدث IDOR عندما يعتمد التطبيق على معرف كائن يرسله المستخدم، مثل invoice_id أو user_id أو order_id، دون التحقق من الصلاحية على مستوى الكائن.
مثال:
المستخدم A لديه فاتورة رقم
1001.المستخدم B لديه فاتورة رقم
1002.المستخدم A يغير الرقم في الطلب إلى
1002.إذا أعاد الخادم بيانات فاتورة المستخدم B، فهناك ثغرة IDOR/BOLA.
سيناريو واقعي
تخيل منصة SaaS لإدارة الفواتير. الـ endpoint التالي يستخدمه المستخدمون لعرض فاتورتهم:
GET /api/invoices/1001الخادم يتحقق فقط من أن المستخدم مسجل دخول، ثم ينفذ:
app.get('/api/invoices/:id', authMiddleware, async (req, res) => {
const invoice = await Invoice.findById(req.params.id);
if (!invoice) return res.status(404).end();
res.json(invoice);
});المشكلة هنا أن authMiddleware يثبت الهوية فقط، لكنه لا يتحقق من الصلاحية. لذلك أي مستخدم مسجل دخول يمكنه تغيير الرقم ومعرفة فواتير الآخرين.
الكود الآمن
يجب أن يكون التحقق من الصلاحية مدمجًا في الاستعلام نفسه، وليس مجرد فحص شكلي بعد الجلب:
app.get('/api/invoices/:id', authMiddleware, async (req, res) => {
const invoice = await Invoice.findOne({
_id: req.params.id,
userId: req.user.id
});
if (!invoice) return res.status(404).json({ error: 'Not found' });
res.json(invoice);
});أو باستخدام سياسة صلاحيات مركزية:
const canReadInvoice = (user, invoice) =>
invoice.userId === user.id || user.roles.includes('admin');ثم تُطبق هذه السياسة في كل نقطة وصول، مع تفضيل دمج شرط الملكية في الاستعلام لتقليل خطر النسيان.
لماذا لا يكفي استخدام UUID؟
كثيرون يعتقدون أن استخدام UUID بدلًا من الأرقام التسلسلية يحل المشكلة. هذا غير صحيح.
UUID يقلل من قابلية التخمين، لكنه قد يتسرب عبر:
سجلات الخادم
ترويسة Referer
لقطات الشاشة
مشاركة الروابط
تطبيقات الطرف الثالث
لذلك، UUID طبقة دفاع إضافية فقط، وليس بديلًا عن التحقق من الصلاحية.
التأثير المحتمل
تسريب بيانات حساسة لمستخدمين آخرين.
تعديل أو حذف بيانات لا يملك المستخدم صلاحية الوصول إليها.
تجاوز حدود الاشتراك أو الدفع.
مشاكل امتثال مثل GDPR أو PCI DSS.
فقدان ثقة العملاء.
كيف تختبر بشكل آمن؟
لا تختبر أي نظام دون تصريح مكتوب. الاختبار يكون في بيئة مختبرية أو نظام تملكه:
أنشئ حسابين: A و B.
أنشئ عنصرًا لكل حساب، مثل فاتورة أو طلب.
سجل الدخول بحساب A.
بدل معرف عنصر B في الطلب.
راقب الاستجابة: إذا أعادت البيانات، فهناك ثغرة.
كرر الاختبار على
GETوPUTوPATCHوDELETE.
الحماية المقترحة
مبدأ Deny by default.
مصادقة ثم تصريح لكل كائن.
التحقق من الملكية أو الدور في طبقة الوصول للبيانات.
استخدام معرفات غير مباشرة عند الحاجة.
اختبارات آلية لكل endpoint بحسابين مختلفين.
تسجيل ومراقبة محاولات الوصول غير المصرح بها.
عدم الاعتماد على إخفاء الحقول في الواجهة الأمامية.
إرجاع 404 بدل 403 أحيانًا لتقليل تسريب وجود الكائن.
الردود والمناقشات التقنية 0
كن أول من يشارك رأيه أو استفساره التقني حول هذا الموضوع
إضافة رد أو استفسار تقني
يجب تسجيل الدخول لإضافة ردود ومشاركة الأكواد في هذا الموضوع.