حماية واجهات API من إساءة الاستخدام: Rate Limiting واستراتيجيات أخرى

حماية واجهات API من إساءة الاستخدام: Rate Limiting واستراتيجيات أخرى

تطبيقات الويب الحديثة تعتمد بشكل أساسي على واجهات API للتواصل بين الواجهة الأمامية، والخدمات الخلفية، والتطبيقات الخارجية. ومع ازدياد عدد المستخدمين والخدمات المتصلة، يصبح من الضروري جدًا تطبيق حماية API rate limiting واستراتيجيات أخرى لمنع إساءة الاستخدام، الهجمات، أو الاستهلاك غير المنضبط للموارد.

في هذا المقال من افهم صح سنشرح مفهوم التحكم في معدل الطلبات (Rate Limiting)، وسياسات الحظر الذكي، والتحقق من المستخدمين، بالإضافة إلى أدوات جاهزة، مع أمثلة عملية في Flask وFastAPI وDjango.

لماذا نحتاج إلى حماية API باستخدام Rate Limiting؟

الـ Rate Limiting هي آلية لتحديد عدد الطلبات المسموح بها من مستخدم (أو IP أو Token) خلال إطار زمني معين. الهدف منها:

  • منع إساءة الاستخدام (Abuse): مثل كتابة سكربت يرسل آلاف الطلبات في الدقيقة.
  • حماية من هجمات DoS و DDoS على مستوى التطبيق.
  • ضمان عدالة توزيع الموارد بين المستخدمين وعدم احتكارها من عميل واحد.
  • تقليل التكلفة خاصة في الخدمات السحابية التي تدفع حسب الاستهلاك.

في مقال آخر تحدثنا عن أفضل ممارسات تصميم RESTful APIs آمن، وذكرنا أن التحكم في معدل الطلبات جزء أساسي من الأمان على مستوى التطبيق.

المفاهيم الأساسية في Rate Limiting

1. تعريف الحصة (Quota) والنافذة الزمنية (Time Window)

حصة الاستخدام هي الحد الأقصى للطلبات المسموحة في فترة زمنية معينة، مثل:

  • 100 طلب لكل دقيقة لكل عنوان IP.
  • 1000 طلب لكل ساعة لكل مستخدم (Token أو User ID).
  • 10 طلبات لكل ثانية لكل خدمة داخلية (Microservice).

النافذة الزمنية يمكن أن تكون ثابتة (Fixed Window) أو متحركة (Sliding Window)، وسنشرح الفرق لاحقًا.

2. مستوى تطبيق الـ Rate Limiting

  • على مستوى IP: مناسب للواجهات العامة، لكنه قد يظلم شركات خلف Proxy واحد.
  • على مستوى المستخدم/الـ Token: أدق، خاصة لو كان لديك نظام تسجيل دخول أو API Keys.
  • على مستوى Endpoint: إعطاء حدود مختلفة للـ Endpoints الحساسة (مثل /login) مقارنة بغيرها.

خوارزميات شائعة لتطبيق Rate Limiting

1. Fixed Window (النافذة الثابتة)

تقسم الزمن إلى نوافذ ثابتة (مثلاً كل دقيقة) وتحسب عدد الطلبات في كل نافذة. إذا تجاوز العميل الحد في النافذة الحالية يتم حظره حتى بداية النافذة التالية.

  • الميزة: سهل التنفيذ.
  • العيب: قد تحدث "انفجارات" في بداية كل نافذة (Burst).

2. Sliding Window (النافذة المتحركة)

بدلاً من نافذة ثابتة، يتم حساب الطلبات خلال آخر X ثانية/دقائق بشكل متحرك. يعطي عدالة أكبر ويقلل مشكلة الانفجارات.

3. Token Bucket و Leaky Bucket

  • Token Bucket: لكل مستخدم "دلو" توكنات؛ تزداد بمعدل ثابت وتُستهلك مع كل طلب. يسمح بانفجارات محدودة ثم يعود إلى المعدل الطبيعي.
  • Leaky Bucket: الطلبات تخرج من الدلو بمعدل ثابت؛ الزائد يتم إسقاطه.

هذه الخوارزميات أكثر استخداماً في الأنظمة كبيرة الحجم لأنها مرنة ويمكن ضبطها بدقة.

استراتيجيات أخرى لحماية واجهات API بجانب Rate Limiting

1. سياسة الحظر الذكي (Smart Blocking)

بدلاً من حظر فوري عند تجاوز الحد، يمكن اتباع سياسة تدريجية:

  1. إنذار أول: إعادة استجابة 429 Too Many Requests مع رسالة توضح الحد المسموح.
  2. تأخير (Throttling): إدخال تأخير بسيط (مثلاً 200-500ms) قبل الاستجابة للطلبات الزائدة.
  3. حظر قصير المدى: حظر لمدة دقيقة/خمس دقائق عند استمرار التجاوز.
  4. حظر أطول: في حال تكرار النمط بشكل واضح، يمكن حظر IP أو Token لمدة أكبر.

هذه السياسة تمنع إساءة الاستخدام من سكربتات آلية، مع مراعاة المستخدمين الشرعيين.

2. التحقق من المستخدمين وخصائصهم

  • استخدام API Keys أو OAuth Tokens للتمييز بين العملاء.
  • إعطاء حدود مختلفة حسب نوع الحساب:
    • مستخدم مجاني: 100 طلب/دقيقة.
    • خطة مدفوعة: 1000 طلب/دقيقة.
  • التحقق من المصدر (Origin) والـ User-Agent لكشف السكربتات البسيطة.

3. Captcha والتحديات الإضافية

في Endpoints حساسة مثل /login أو /reset-password، يمكن إضافة:

  • Captcha بعد عدد محاولات فاشلة.
  • تحديات إضافية (مثل التحقق الثنائي 2FA) عند سلوك مشبوه.

4. استخدام Middleware وReverse Proxy

بدلاً من كتابة كل شيء داخل الكود الأساسي، يمكن استخدام:

  • Middleware داخل إطار العمل (مثلاً في Django، ويمكنك مراجعة شرح Middleware في Django).
  • Nginx / HAProxy / API Gateway لتنفيذ Rate Limiting قبل وصول الطلب إلى التطبيق.
  • خدمات سحابية مثل AWS API Gateway, Cloudflare, Kong…

تطبيق Rate Limiting في Flask مع مثال عملي

في Flask يمكن استخدام مكتبة جاهزة مثل Flask-Limiter لتطبيق حماية API rate limiting بسهولة.

تثبيت المكتبة

pip install flask-limiter

مثال بسيط على استخدام Flask-Limiter


from flask import Flask
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

app = Flask(__name__)

limiter = Limiter(
    get_remote_address,
    app=app,
    default_limits=["100 per minute"]  # حد عام لكل الواجهات
)

@app.route("/api/data")
@limiter.limit("10 per second")  # حد خاص بهذه الواجهة
def get_data():
    return {"message": "OK"}

if __name__ == "__main__":
    app.run()

في المثال السابق:

  • تم وضع حد افتراضي 100 طلب في الدقيقة لكل IP.
  • للـ Endpoint /api/data حد إضافي 10 طلبات في الثانية.

يمكنك أيضًا تخصيص المفتاح المستخدم للـ Rate Limiting ليعتمد على Token بدلاً من IP:


from flask import request

def get_api_key():
    return request.headers.get("X-API-Key") or get_remote_address()

تطبيق Rate Limiting في FastAPI باستخدام SlowAPI أو fastapi-limiter

إطار FastAPI يدعم التكامل بسهولة مع مكتبات خارجية مثل SlowAPI أو fastapi-limiter، وغالبًا تستخدم Redis كـ Storage.

تثبيت fastapi-limiter

pip install fastapi-limiter redis

مثال على استخدام fastapi-limiter


from fastapi import FastAPI, Depends
from fastapi_limiter import FastAPILimiter
from fastapi_limiter.depends import RateLimiter
import aioredis

app = FastAPI()

@app.on_event("startup")
async def startup():
    redis = await aioredis.from_url("redis://localhost", encoding="utf-8", decode_responses=True)
    await FastAPILimiter.init(redis)

@app.get("/api/items", dependencies=[Depends(RateLimiter(times=100, seconds=60))])
async def get_items():
    return {"items": []}

في هذا المثال:

  • يتم تخزين عداد الطلبات في Redis.
  • الحد: 100 طلب لكل 60 ثانية (لكل مفتاح – غالبًا IP).
  • يمكنك تخصيص دالة استخراج المفتاح (مثلاً من Header يحتوي على API Key).

تطبيق Rate Limiting في Django باستخدام Middleware

في Django يمكن استخدام مكتبات جاهزة مثل django-ratelimit، أو بناء Middleware خاص بك. الاستفادة من Middleware في هذه الحالة قوية؛ لأنه يستطيع اعتراض الطلبات قبل وصولها إلى الـ View. لمزيد من التفاصيل حول Middleware راجع: شرح طريقة استخدام Middleware في Django.

تثبيت django-ratelimit

pip install django-ratelimit

الإعداد في settings.py


INSTALLED_APPS = [
    # ...
    'ratelimit',
]

استخدامه في الـ Views


from django.http import HttpResponse
from ratelimit.decorators import ratelimit

@ratelimit(key='ip', rate='5/m', block=True)
def my_view(request):
    return HttpResponse("OK")

في هذا المثال:

  • key='ip': تطبيق الـ Rate Limiting لكل IP.
  • rate='5/m': 5 طلبات في الدقيقة.
  • block=True: حظر الطلب مباشرة وإرجاع 429 عند التجاوز.

يمكنك أيضًا تحديد مفتاح مختلف مثل:

  • key='user' للمستخدم المسجل.
  • أو key='user_or_ip' للجمع بينهما.

مثال Middleware بسيط للتوضيح

الهدف من الكود التالي تعليمي (ليس للإنتاج)، يوضح فكرة العد على مستوى الـ IP باستخدام Cache:


# middleware.py
import time
from django.core.cache import cache
from django.http import JsonResponse

class SimpleRateLimitMiddleware:
    RATE = 100  # 100 طلب
    WINDOW = 60  # في 60 ثانية

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        ip = request.META.get('REMOTE_ADDR', 'unknown')
        key = f"rl:{ip}"
        data = cache.get(key, {'count': 0, 'start': time.time()})

        now = time.time()
        if now - data['start'] > self.WINDOW:
            data = {'count': 0, 'start': now}

        data['count'] += 1
        cache.set(key, data, timeout=self.WINDOW)

        if data['count'] > self.RATE:
            return JsonResponse(
                {"detail": "Too many requests"},
                status=429
            )

        response = self.get_response(request)
        return response

ثم تضيف الـ Middleware في MIDDLEWARE داخل settings.py.

أين نخزن بيانات الـ Rate Limiting؟

اختيار مكان تخزين العدادات يؤثر على الأداء والدقة:

  • In-Memory (RAM) داخل التطبيق:
    • سريع وبسيط.
    • غير مناسب للتطبيقات متعددة النسخ (أكثر من Server واحد) لأنه لا يوجد تزامن بينها.
  • Redis / Memcached:
    • الخيار الشائع؛ سريع، خارجي، ويدعم الـ Atomic Operations.
    • مناسب للأنظمة الموزعة.
  • قاعدة بيانات SQL/NoSQL:
    • أبطأ نسبيًا، ولكن يمكن استخدامها مع حدود كبيرة (مثلاً 1000 طلب/اليوم) أو للتقارير.

أفضل الممارسات لتصميم سياسة Rate Limiting فعّالة

  1. تمييز أنواع العملاء:
    • مستخدم بشري (متصفح) مقابل سكربت/خدمة.
    • حساب مجاني مقابل مدفوع.
  2. وضع حدود متعددة المستويات:
    • حد لكل ثانية (Burst).
    • حد لكل دقيقة.
    • حد لكل يوم أو شهر (Quota).
  3. توفير معلومات واضحة للمستخدمين:
    • استخدام Header مثل X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
    • توضيح سياسة الـ Rate Limiting في التوثيق الخاص بالـ API.
  4. عمل استثناءات للخدمات الداخلية:
    • خدمات داخلية موثوقة يمكن إعفاؤها أو إعطاؤها حدودًا عالية مع مراقبة.
  5. البدء بحدود محافظة ثم التعديل:
    • راقب سجلات الطلبات (Logs) ثم اضبط القيم وفقًا لسلوك المستخدمين.

التكامل مع الأمان العام لواجهات RESTful APIs

الـ Rate Limiting وحده لا يكفي؛ يجب دمجه مع:

خلاصة

حماية واجهات API من إساءة الاستخدام ليست خيارًا إضافيًا؛ بل ضرورة لأي نظام يعتمد على الإنترنت. استخدام حماية API rate limiting مع:

  • سياسات حظر ذكي تدريجية.
  • التحقق من هوية المستخدمين وتفريق الخطط (Free/Pro).
  • تطبيق Middleware على مستوى التطبيق أو API Gateway أمامه.
  • استخدام أدوات جاهزة في Flask وFastAPI وDjango.

سيساعدك على بناء واجهات مستقرة، آمنة، وتتحمل عددًا كبيرًا من المستخدمين دون سقوط أو استهلاك مفرط للموارد. ابدأ بتحديد حدود معقولة، راقب السلوك، وعدّل القيم والخوارزميات حتى تصل إلى التوازن بين الأمان وتجربة الاستخدام الجيدة.

حول المحتوى:

شرح تقنيات التحكم في معدل الطلبات، سياسة الحظر الذكي، التحقق من المستخدمين، واستخدام أدوات جاهزة مع أمثلة لتطبيقات Flask وFastAPI وDjango.

هل كان هذا مفيدًا لك؟

أضف تعليقك