ثغرات الـ API التي يقع فيها كل مطور
OWASP Top 10 بأمثلة كود حقيقية وحلول فورية
BOLA، Broken Auth، تسريب API Keys في GitHub — مشاكل تقنية حقيقية دمّرت شركات كاملة. تعلّم كيف تكتشفها في كودك وتصلحها قبل أن يستغلها أحد.
📡 لماذا الـ API هي الهدف الأول للمهاجمين في 2026؟
الـ API لم تعد مجرد واجهة تقنية — أصبحت شريان الحياة الرقمي للشركات. كل طلب دفع، كل تسجيل دخول، كل تكامل بين خدمتين — يمر عبر API. وبالتالي أصبحت الهدف الأول لأي مهاجم يبحث عن بيانات أو صلاحيات.
المشكلة الأساسية: المطورون يبنون APIs بسرعة كبيرة — خصوصاً مع مساعدات الـ AI مثل Copilot وCursor — لكن الكود المُولَّد غالباً لا يتبع best practices الأمنية. النتيجة: ثغرات تُنشر مع أول deployment.
🔓 BOLA — Broken Object Level Authorization
BOLA تحدث حين يتحقق الـ API من أن المستخدم مُسجّل الدخول فقط، لكنه لا يتحقق من أنه يملك صلاحية الوصول لهذا المورد بالذات. المهاجم ببساطة يُغيّر رقم الـ ID في الـ request ويصل لبيانات مستخدمين آخرين.
اختُرقت بسببها شركات كبرى: Uber 2016، Facebook 2018، Trello 2024 — جميعها كشفت بيانات ملايين المستخدمين.
❌ الكود المعطوب — هل لديك هذا في مشروعك؟
# ❌ خطأ شائع — لا يوجد تحقق من الملكية @app.route('/api/orders/<int:order_id>', methods=['GET']) @login_required def get_order(order_id): # ⚠️ يجلب الطلب بالـ ID مباشرة بدون أي تحقق order = Order.query.get(order_id) if not order: return jsonify({'error': 'Not found'}), 404 # ⚠️ لم يتحقق هل هذا الطلب يخص المستخدم الحالي! return jsonify(order.to_dict()) # المهاجم يرسل: GET /api/orders/1337 ويقرأ طلبات أي مستخدم
✅ الحل الصحيح — أضف هذا الكود
# ✅ صح — التحقق من ملكية المورد قبل إرجاعه @app.route('/api/orders/<int:order_id>', methods=['GET']) @login_required def get_order(order_id): # ✅ اجلب هوية المستخدم من الـ JWT token current_user_id = get_jwt_identity() # ✅ تحقق من الملكية في نفس الـ query order = Order.query.filter_by( id=order_id, user_id=current_user_id # ← هذا هو المفتاح ).first() if not order: # ✅ 404 وليس 403 — لا تكشف وجود المورد return jsonify({'error': 'Not found'}), 404 return jsonify(order.to_dict()) # المهاجم الآن يحصل على 404 حتى لو كان الطلب موجوداً
🔍 كيف تختبر BOLA في API الخاص بك؟
# 1. سجّل دخول بحساب User A واحصل على token TOKEN_A="eyJhbGci..." # 2. اجلب موردك الخاص curl -X GET https://api.example.com/orders/100 \ -H "Authorization: Bearer $TOKEN_A" # ✅ يجب أن يرجع 200 # 3. حاول تغيير الـ ID لمورد مستخدم آخر curl -X GET https://api.example.com/orders/101 \ -H "Authorization: Bearer $TOKEN_A" # ✅ يجب أن يرجع 404 — إذا رجع 200 فلديك ثغرة BOLA!
القاعدة الذهبية: دائماً استخدم UUIDs بدلاً من sequential integers كـ IDs. UUID مثل f47ac10b-58cc-4372-a567-0e02b2c3d479 يصعب تخمينه — لكنه لا يُغني عن التحقق من الصلاحيات!
🔑 Broken Authentication — المصادقة المكسورة
تشمل كل خلل في آلية التحقق من هوية المستخدم: JWT tokens ضعيفة أو منتهية الصلاحية لا تُرفض، API keys مكشوفة، refresh tokens لا تُلغى بعد تسجيل الخروج، وغياب الحماية من Brute-Force.
❌ أخطاء JWT الأكثر شيوعاً
// ❌ خطأ 1: السماح بخوارزمية "none" const decoded = jwt.verify(token, secret, { algorithms: ['HS256', 'none'] // ⚠️ خطر جداً! }); // ❌ خطأ 2: JWT بدون انتهاء صلاحية const token = jwt.sign( { userId: user.id }, process.env.JWT_SECRET // ⚠️ لا يوجد expiresIn — يصلح للأبد! ); // ❌ خطأ 3: secret ضعيف const JWT_SECRET = "secret"; // ⚠️ قابل للتخمين
// ✅ صح — JWT محكم وآمن const token = jwt.sign( { userId: user.id, role: user.role, jti: uuidv4() // ✅ معرف فريد للـ token }, process.env.JWT_SECRET, // ✅ من متغيرات البيئة { algorithm: 'HS256', // ✅ خوارزمية صريحة expiresIn: '15m', // ✅ 15 دقيقة فقط issuer: 'api.myapp.com' // ✅ مصدر محدد } ); // ✅ التحقق مع تحديد الخوارزمية فقط const decoded = jwt.verify(token, process.env.JWT_SECRET, { algorithms: ['HS256'], // ✅ لا "none" أبداً issuer: 'api.myapp.com' });
✅ حماية Rate Limiting من Brute-Force
const rateLimit = require('express-rate-limit'); const RedisStore = require('rate-limit-redis'); // ✅ حماية endpoint تسجيل الدخول const loginLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 دقيقة max: 5, // ✅ 5 محاولات فقط message: { error: 'Too many attempts, try again later' }, store: new RedisStore({ ... }), // ✅ Redis لـ distributed systems standardHeaders: true, legacyHeaders: false, // ✅ Block بالـ IP + username معاً keyGenerator: (req) => `${req.ip}:${req.body.email}` }); app.post('/api/auth/login', loginLimiter, authController.login);
T-Mobile 2023 — 37 مليون مستخدم بسبب API مكشوف
اكتشف أحد الباحثين API endpoint في T-Mobile لا يتطلب مصادقة على الإطلاق. بمجرد معرفة رقم الهاتف يمكن جلب بيانات الحساب الكاملة. المهاجم جمع بيانات 37 مليون مستخدم قبل الاكتشاف. الدرس: كل endpoint يحتاج authentication — بدون استثناء.
📤 Broken Object Property Level Authorization — تسريب البيانات الزائدة
يحدث حين يُرجع الـ API كل حقول الـ object من قاعدة البيانات مباشرة، بدلاً من إرجاع الحقول المسموح بها فقط. مشكلة Mass Assignment تحدث حين يقبل الـ API تحديث حقول حساسة كـ isAdmin أو role من المستخدم مباشرة.
# ❌ خطأ — إرجاع كل بيانات المستخدم بدون فلترة @app.get("/users/{user_id}") async def get_user(user_id: int): user = await db.get_user(user_id) return user.__dict__ # ⚠️ يرجع password_hash, role, internal_notes... # ❌ Mass Assignment — يقبل تحديث أي حقل @app.put("/users/{user_id}") async def update_user(user_id: int, data: dict): await db.update_user(user_id, **data) # ⚠️ يقبل {isAdmin: true}!
from pydantic import BaseModel from typing import Optional # ✅ Response schema — يحدد ما يُرجع فقط class UserPublicResponse(BaseModel): id: int username: str email: str created_at: str # ✅ لا password_hash، لا role، لا internal_notes # ✅ Update schema — يحدد ما يمكن تعديله فقط class UserUpdateRequest(BaseModel): username: Optional[str] = None bio: Optional[str] = None # ✅ لا isAdmin، لا role، لا permissions @app.get("/users/{user_id}", response_model=UserPublicResponse) async def get_user(user_id: int): user = await db.get_user(user_id) return user # ✅ Pydantic يفلتر تلقائياً @app.put("/users/{user_id}") async def update_user(user_id: int, data: UserUpdateRequest): await db.update_user(user_id, **data.dict(exclude_unset=True))
⚡ Unrestricted Resource Consumption — بدون Rate Limiting
API بدون rate limiting يمكن استخدامه لـ: استنزاف موارد السيرفر حتى يتوقف، scraping البيانات بشكل آلي، أو إرسال آلاف رسائل SMS/Email على حسابك. المهاجم يُشغّل loop بسيط ويُكلّفك الآلاف.
# settings.py REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': [ 'rest_framework.throttling.AnonRateThrottle', 'rest_framework.throttling.UserRateThrottle', ], 'DEFAULT_THROTTLE_RATES': { 'anon': '100/hour', # ✅ زوار غير مسجلين 'user': '1000/hour', # ✅ مستخدمين مسجلين 'login': '5/minute', # ✅ تسجيل الدخول 'otp': '3/hour', # ✅ رموز OTP 'sms': '10/day', # ✅ إرسال SMS } } # views.py class SendOTPView(APIView): # ✅ throttle_classes خاص لهذا الـ endpoint throttle_classes = [ScopedRateThrottle] throttle_scope = 'otp' def post(self, request): # إرسال OTP بأمان ...
لا تنسَ: Rate limiting يجب أن يكون على مستوى الـ IP والـ User معاً. المهاجم يمكنه استخدام حسابات مختلفة لتجاوز حد مستخدم واحد.
🗝️ تسريب API Keys في GitHub — المشكلة التي تدمر الشركات
في 2025، وجد باحثو CybelAngel أكثر من 30,000 Postman workspace تحتوي API keys ورموز وصول حية مكشوفة للعموم. وفي GitHub، يُرفع آلاف الـ secrets كل يوم عن طريق الخطأ. هذه المشكلة تحدث لمطورين محترفين في شركات كبرى.
مطور رفع .env file على GitHub العام — خسر $47,000 في ساعات
رفع مطور مشروعه على GitHub ونسي حذف ملف .env الذي يحتوي AWS credentials. خلال ساعة واحدة، اكتشفها bot يُمسح GitHub باستمرار. أنشأ المهاجم 200 EC2 instance لتعدين العملات الرقمية. الفاتورة: $47,000 في أقل من 24 ساعة.
❌ الأخطاء الأكثر شيوعاً في التعامل مع الـ Secrets
# ❌ أسوأ ما يمكن فعله AWS_ACCESS_KEY = "AKIAIOSFODNN7EXAMPLE" # ⚠️ مباشرة في الكود DB_PASSWORD = "mypassword123" # ⚠️ مرئي في Git history STRIPE_SECRET = "sk_live_abcdefghijk" # ⚠️ حتى لو حذفته لاحقاً # ❌ في ملف config.js const config = { apiKey: "AIzaSyD-9tSrke72...", // ⚠️ سيظهر في GitHub databaseURL: "https://..." };
# ✅ ملف .env (مُدرج في .gitignore) AWS_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE DB_PASSWORD=mypassword123 STRIPE_SECRET=sk_live_abcdefghijk # ✅ في الكود — اقرأ من البيئة فقط import os from dotenv import load_dotenv load_dotenv() AWS_ACCESS_KEY = os.getenv('AWS_ACCESS_KEY') DB_PASSWORD = os.getenv('DB_PASSWORD') # ✅ تحقق من وجود الـ secrets عند البدء required_secrets = ['AWS_ACCESS_KEY', 'DB_PASSWORD', 'STRIPE_SECRET'] for secret in required_secrets: if not os.getenv(secret): raise ValueError(f"Missing required secret: {secret}")
✅ إعداد .gitignore الصحيح من اليوم الأول
# Secrets & Credentials .env .env.local .env.production .env.*.local *.pem *.key *_rsa *_dsa secrets.json credentials.json service-account.json # AWS .aws/ aws-credentials # IDE .idea/ .vscode/settings.json # Logs *.log logs/
🔍 افحص إذا رفعت secrets بالخطأ سابقاً
# ✅ أداة trufflehog — تفحص الـ Git history كاملاً pip install trufflehog trufflehog git file://./ --only-verified # ✅ أداة gitleaks — أسرع وأشمل brew install gitleaks gitleaks detect --source . -v # ✅ إذا وجدت secret في الـ history، أزله بالكامل # (لا يكفي حذفه في commit جديد — الـ history لا يزال موجوداً) git filter-repo --path .env --invert-paths # ثم أعد رفع الـ repo وأبطل كل الـ secrets القديمة
مهم جداً: حذف الـ secret في commit جديد لا يكفي — الـ Git history لا يزال يحتوي القيمة القديمة. الحل الوحيد: أبطل الـ secret فوراً وأصدر واحداً جديداً، بغض النظر عن أي شيء آخر.
🧰 أدوات فحص أمان الـ API
هذه الأدوات يستخدمها مختبرو الاختراق وفرق الأمن يومياً. معظمها مجاني ومفتوح المصدر.
OWASP ZAP
فحص تلقائي شامل لثغرات OWASP Top 10. مثالي للبدء
مجانيBurp Suite
المعيار الصناعي لاختبار الاختراق. نسخة Community مجانية
Community مجانيNuclei
فحص سريع بـ templates جاهزة. آلاف القوالب من المجتمع
مجانيTrufflehog
فحص الـ Git history عن secrets مسرّبة بدقة عالية
مجانيGitleaks
اكتشاف secrets في الـ repos قبل النشر. يندمج مع CI/CD
مجاني42Crunch
تحليل ثابت لملفات OpenAPI/Swagger لاكتشاف الثغرات
مدفوع / نسخة تجريبية# تثبيت Nuclei go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest # ✅ فحص الـ API بقوالب متخصصة nuclei -u https://api.example.com \ -t api/ \ -severity critical,high \ -o results.txt # ✅ فحص ملف OpenAPI spec nuclei -t exposures/apis/ \ -u https://api.example.com/swagger.json
✅ Checklist أمان الـ API قبل كل Deployment
احفظ هذا الـ checklist وطبّقه قبل كل نشر. كل نقطة تمنع ثغرة حقيقية.
🎯 الخلاصة للمطور
الـ API الآمن ليس ترفاً — إنه المسؤولية الأساسية. كل سطر كود تكتبه اليوم هو إما سور حماية أو ثغرة مفتوحة. طبّق هذا الـ checklist، أضف الأدوات لـ CI/CD pipeline، واجعل الأمن جزءاً من الكود وليس فكرة لاحقة.
❓ الأسئلة الأكثر بحثاً
ما الفرق بين BOLA وIDOR؟
BOLA (Broken Object Level Authorization) هو المصطلح الرسمي في OWASP لما يُعرف سابقاً بـ IDOR (Insecure Direct Object Reference). هما نفس الثغرة — الوصول لمورد لا تملكه بتغيير الـ ID. OWASP اعتمد مصطلح BOLA لأنه أكثر دقة ويشمل حالات أوسع من مجرد تغيير رقم في الـ URL.
هل UUID يحمي من BOLA؟
UUID يُصعّب التخمين لكنه لا يُحمّي من BOLA. المشكلة الأساسية هي غياب تحقق الصلاحيات — إذا حصل المهاجم على UUID بأي طريقة (من response آخر مثلاً) سيستطيع الوصول للمورد. UUID هو طبقة دفاع إضافية، وليس الحل الكامل. دائماً أضف user_id = current_user_id في الـ query.
ما أفضل مكتبة لإدارة JWT في Node.js؟
مكتبة jsonwebtoken هي الأكثر استخداماً وموثوقية. تأكد دائماً من تحديد الخوارزمية صراحةً algorithms: ['HS256']، وتعيين وقت انتهاء الصلاحية expiresIn، وتحديد الـ issuer. لمشاريع أكبر، فكّر في jose كبديل أكثر أماناً.
كيف أحمي API Keys في CI/CD pipeline؟
استخدم خدمات Secret Management المدمجة مع منصتك: GitHub Actions Secrets، GitLab CI Variables، أو AWS Secrets Manager. لا تضع الـ secrets في ملفات الـ config أو متغيرات بيئة pipeline مرئية. أضف أداة مثل gitleaks كـ pre-commit hook وكـ CI/CD step.
هل GraphQL APIs لها نفس ثغرات REST؟
نعم وأكثر. GraphQL يضيف مخاطر إضافية: Introspection في الـ Production يكشف كل الـ schema للمهاجم — أوقفها دائماً. Query Depth Attacks — قيّد عمق الاستعلام. N+1 Queries التي تستنزف قاعدة البيانات. تحقق من BOLA بتغيير الـ IDs في الـ GraphQL queries مثلما تفعل مع REST.
ما أسرع طريقة لفحص API الخاص بي الآن؟
ابدأ بـ 3 خطوات فورية: أولاً شغّل gitleaks detect --source . -v في مشروعك للتأكد من عدم وجود secrets. ثانياً جرّب تغيير الـ IDs في طلباتك يدوياً وتحقق من الردود. ثالثاً ثبّت OWASP ZAP وشغّله على بيئة الـ staging قبل أي deployment. هذه الخطوات الثلاث تكشف 80% من المشاكل الشائعة.
📊 ملخص الثغرات والحلول
| الثغرة | OWASP | الخطورة | الحل الأساسي | وقت التطبيق |
|---|---|---|---|---|
| BOLA / IDOR | API1 | Critical | تحقق من ملكية الـ object في كل query | ساعة |
| Broken Auth | API2 | Critical | JWT صحيح + Rate Limiting + MFA | يوم |
| Excessive Data | API3 | High | Response schemas + Whitelist للحقول | ساعات |
| No Rate Limiting | API4 | High | Rate limiting على كل endpoint | ساعة |
| API Key Leak | — | Critical | Environment variables + .gitignore | 30 دقيقة |
