تحديد معدل واجهات API: الخوارزميات والتنفيذ
واجهة API الخاصة بك تحت الهجوم. ليس من قبل قراصنة متطورين، بل من خلال نص برمجي بسيط يضرب نقاط النهاية الخاصة بك آلاف المرات في الثانية، مما يستهلك الموارد ويؤدي إلى تدهور الخدمة للمستخدمين الشرعيين. بدون تحديد المعدل، يمكن لعميل واحد سيئ السلوك أن يسقط تطبيقك بالكامل. يشرح هذا الدليل الخوارزميات الأساسية ويوضح التنفيذ العملي في Node.js و Nginx لحماية واجهة API الخاصة بك.
لماذا يهم تحديد المعدل
يتحكم تحديد المعدل في عدد الطلبات التي يمكن للعميل إجراؤها في نافذة زمنية معينة. إنه خط الدفاع الأول ضد:
- هجمات القوة الغاشمة على نقاط نهاية تسجيل الدخول أو مفتاح API
- هجمات حجب الخدمة (DoS) من الطلبات المفرطة
- استنزاف الموارد من العمليات المكلفة مثل استعلامات قاعدة البيانات أو معالجة الملفات
- إساءة استخدام الطبقات المجانية من قبل أدوات الكشط أو الروبوتات
بجانب الأمان، يضمن تحديد المعدل الاستخدام العادل ويساعدك على فرض قواعد العمل، مثل خطط التسعير المتدرجة.
خوارزميات تحديد المعدل
تهيمن أربع خوارزميات على تحديد معدل API. لكل منها مقايضات في الدقة واستخدام الذاكرة والتعامل مع الانفجارات.
1. النافذة الثابتة
عد الطلبات في فترات زمنية ثابتة (مثل 100 طلب في الدقيقة). عند إعادة تعيين النافذة، يتم إعادة تعيين العداد.
- الإيجابيات: بسيط، ذاكرة منخفضة (عداد واحد لكل عميل).
- السلبيات: انفجار عند حدود النافذة. يمكن للعميل إرسال 100 طلب في 12:00:59 و100 آخر في 12:01:00، مما يعني 200 طلب في ثانيتين.
2. النافذة المنزلقة
تتبع الطوابع الزمنية لكل طلب وعد عدد الطلبات التي تقع ضمن آخر N ثانية. هذا يخفف الانفجارات.
- الإيجابيات: دقيق، لا ارتفاعات على الحدود.
- السلبيات: استخدام ذاكرة أعلى (تخزين الطوابع الزمنية) أو استخدام عداد نافذة منزلقة مع متوسط مرجح.
3. دلو الرموز
يحتوي الدلو على رموز. تضاف الرموز بمعدل ثابت. كل طلب يستهلك رمزًا واحدًا. إذا كان الدلو فارغًا، يتم رفض الطلب.
- الإيجابيات: يسمح بالانفجارات حتى حجم الدلو، ثم يفرض المعدل المتوسط.
- السلبيات: يتطلب تخزين عدد الرموز ووقت آخر إعادة تعبئة لكل عميل.
4. الدلو المثقوب
تدخل الطلبات إلى قائمة انتظار (دلو) وتتم معالجتها بمعدل ثابت. إذا كانت قائمة الانتظار ممتلئة، يتم إسقاط الطلبات.
- الإيجابيات: يخفف حركة المرور إلى معدل ثابت، مثالي لحماية الخدمات اللاحقة.
- السلبيات: يضيف زمن انتقال؛ غير مناسب لواجهات API في الوقت الفعلي.
| الخوارزمية | التعامل مع الانفجارات | الذاكرة | حالة الاستخدام |
|---|---|---|---|
| النافذة الثابتة | ضعيف | منخفضة | واجهات API البسيطة |
| النافذة المنزلقة | جيد | متوسطة | أغراض عامة |
| دلو الرموز | ممتاز | متوسطة | واجهات API مع تحمل الانفجارات |
| الدلو المثقوب | لا شيء | متوسطة | تخفيف حركة المرور |
تنفيذ تحديد المعدل في Node.js
سنقوم بتنفيذ محدد معدل دلو الرموز باستخدام Express و Redis للحالة الموزعة. Redis ضروري عندما يكون لديك عدة نسخ من الخادم.
الخطوة 1: تثبيت التبعيات
npm install express redis
الخطوة 2: إنشاء برمجية تحديد المعدل الوسيطة
const redis = require('redis');
const client = redis.createClient();
async function tokenBucketLimiter(req, res, next) {
const key = `rate_limit:${req.ip}`;
const capacity = 10; // max tokens
const refillRate = 1; // tokens per second
const now = Date.now();
const data = await client.hGetAll(key);
let tokens = data.tokens ? parseFloat(data.tokens) : capacity;
let lastRefill = data.lastRefill ? parseInt(data.lastRefill) : now;
// Refill tokens based on elapsed time
const elapsed = (now - lastRefill) / 1000;
tokens = Math.min(capacity, tokens + elapsed * refillRate);
if (tokens < 1) {
return res.status(429).json({ error: 'Too many requests' });
}
tokens -= 1;
await client.hSet(key, {
tokens: tokens.toString(),
lastRefill: now.toString()
});
await client.expire(key, 60); // auto-cleanup
next();
}
app.use(tokenBucketLimiter);
تتحقق هذه البرمجية الوسيطة من عدد الرموز وتحدّثه بشكل ذري. للإنتاج، استخدم معاملات Redis أو نصوص Lua لتجنب حالات التسابق.
تنفيذ تحديد المعدل في Nginx
يوفر Nginx تحديد معدل مدمج مع وحدة limit_req. يستخدم خوارزمية الدلو المثقوب.
الخطوة 1: تحديد منطقة تحديد المعدل
في كتلة http من nginx.conf:
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
هذا ينشئ منطقة بحجم 10 ميجابايت باسم api تسمح بـ 10 طلبات في الثانية لكل IP.
الخطوة 2: تطبيق الحد
في كتلة location الخاصة بك:
location /api/ {
limit_req zone=api burst=20 nodelay;
proxy_pass http://backend;
}
burst=20 يسمح بانفجارات قصيرة تصل إلى 20 طلبًا. nodelay يعالج طلبات الانفجار فورًا بدلاً من وضعها في قائمة الانتظار.
أفضل الممارسات لتحديد معدل API
- إرجاع رموز الحالة المناسبة: استخدم
429 Too Many Requestsوقم بتضمين ترويسةRetry-After. - تحديد العملاء بشكل صحيح: استخدم مفاتيح API أو معرفات المستخدم بدلاً من عناوين IP عندما يكون ذلك ممكنًا، حيث يمكن مشاركة عناوين IP (NAT) أو انتحالها.
- توزيع الحالة: استخدم Redis أو مخزن مشابه لنشرات متعددة النسخ.
- التسجيل والمراقبة: تتبع حالات تحديد المعدل لاكتشاف الهجمات وضبط العتبات. أدوات مثل محلل سجلات Nginx يمكن أن تساعدك في تحليل استجابات 429 وتحديد عناوين IP المسيئة.
- التواصل حول الحدود: وثّق حدود المعدل في وثائق API الخاصة بك وقم بتضمين ترويسات مثل
X-RateLimit-Limit،X-RateLimit-Remaining.
الأسئلة الشائعة
ما الفرق بين تحديد المعدل والخنق؟
تحديد المعدل يحظر الطلبات التي تتجاوز عتبة معينة، بينما الخنق يبطئها (على سبيل المثال، عن طريق وضعها في قائمة الانتظار أو تأخيرها). تحديد المعدل ثنائي؛ الخنق تدريجي.
أي خوارزمية تحديد معدل يجب أن أستخدم؟
لمعظم واجهات API، يوفر دلو الرموز توازنًا جيدًا: يسمح بالانفجارات لكنه يفرض معدلًا متوسطًا. إذا كنت بحاجة إلى تخفيف صارم، استخدم الدلو المثقوب. للبساطة، تعمل النافذة الثابتة لواجهات API منخفضة الحركة.
كيف أتعامل مع تحديد المعدل للمستخدمين المصادق عليهم مقابل المجهولين؟
طبق حدودًا أكثر صرامة على المستخدمين المجهولين (على سبيل المثال، حسب IP) وحدودًا أكثر سخاءً على المستخدمين المصادق عليهم (على سبيل المثال، حسب مفتاح API). يمكنك أيضًا تنفيذ حدود متدرجة بناءً على خطط الاشتراك.
هل أنت مستعد لتحليل حركة مرور API الخاصة بك؟ استخدم محلل سجلات Nginx الخاص بنا لتحليل السجلات، واكتشاف انتهاكات تحديد المعدل، وتحسين العتبات الخاصة بك.