شرح Webhooks: الحمولات الموقعة واستراتيجيات إعادة المحاولة
لقد قمت ببناء واجهة برمجة تطبيقات (API) ترسل webhooks إلى نقاط نهاية المستخدمين. ولكن بعد ذلك تواجه المشكلات الكلاسيكية: كيف تضمن أن الحمولة لم يتم التلاعب بها؟ ماذا يحدث عندما تكون نقطة النهاية معطلة؟ كيف تمنع المعالجة المكررة؟ في هذه المقالة، سنتعامل مع هذه التحديات مباشرة باستخدام الحمولات الموقعة واستراتيجيات إعادة المحاولة القوية.
لماذا تحتاج webhooks إلى توقيعات
webhooks هي عمليات استدعاء HTTP (callbacks) تُعلم الأنظمة الأخرى بالأحداث. نظرًا لأنها تُرسل عبر الإنترنت العام، فهي عرضة للاعتراض والانتحال. بدون توقيع، يمكن لجهة خبيثة إرسال webhooks مزيفة إلى مستخدميك، مما يؤدي إلى إجراءات غير مقصودة. توقيع الحمولات باستخدام سر مشترك يضمن الأصالة والسلامة.
كيف تعمل الحمولات الموقعة
النهج الأكثر شيوعًا هو HMAC (رمز المصادقة القائم على التجزئة) مع SHA-256. يشترك المرسل والمستقبل في مفتاح سري. يحسب المرسل توقيعًا على الحمولة (وأحيانًا طابع زمني) ويضمنه في ترويسة. يعيد المستقبل حساب التوقيع ويقارنه بالتوقيع المستلم.
خطوة بخطوة: توقيع الحمولة
- إنشاء الحمولة: قم بتسلسل بيانات الحدث إلى JSON. تأكد من التنسيق المتسق (مثل عدم وجود مسافات إضافية) لأن التوقيع يُحسب على البايتات الدقيقة.
- إضافة طابع زمني: قم بتضمين طابع زمني Unix في الحمولة أو الترويسة لمنع هجمات إعادة التشغيل. يمكن للمستقبل رفض الطلبات الأقدم من بضع دقائق.
- حساب HMAC: استخدم مفتاحك السري لتوليد HMAC-SHA256 لسلسلة الحمولة (أو الطابع الزمني + الحمولة).
- إرفاق التوقيع: أرسله في ترويسة مثل
X-Signature.
إليك مثالاً في Python:
import hmac
import hashlib
import json
import time
secret = b'your_shared_secret'
payload = {"event": "user.created", "data": {"id": 123}}
body = json.dumps(payload, separators=(',', ':'))
timestamp = str(int(time.time()))
signed_content = timestamp + '.' + body
signature = hmac.new(secret, signed_content.encode(), hashlib.sha256).hexdigest()
# Send headers: X-Signature: signature, X-Timestamp: timestamp
التحقق من التوقيع
على الجانب المستقبل، يجب عليك:
- استخراج الطابع الزمني والتوقيع من الترويسات.
- الرفض إذا كان الطابع الزمني قديمًا جدًا (مثل >5 دقائق) لمنع هجمات إعادة التشغيل.
- إعادة حساب التوقيع باستخدام نفس الطريقة.
- المقارنة باستخدام دالة زمن ثابت لتجنب هجمات التوقيت.
مثال التحقق في Node.js:
const crypto = require('crypto');
function verifySignature(req, secret) {
const signature = req.headers['x-signature'];
const timestamp = req.headers['x-timestamp'];
if (!signature || !timestamp) return false;
if (Date.now() / 1000 - timestamp > 300) return false; // 5 min
const body = JSON.stringify(req.body);
const signed = timestamp + '.' + body;
const expected = crypto.createHmac('sha256', secret).update(signed).digest('hex');
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
تصميم استراتيجيات إعادة المحاولة
حتى مع التوقيعات، يمكن أن تفشل webhooks بسبب مشكلات الشبكة أو أخطاء الخادم أو المهلات. استراتيجية إعادة المحاولة القوية تضمن التسليم دون إغراق المستقبل.
الاعتبارات الرئيسية
- Idempotency: يجب على المستقبلين التعامل مع الأحداث المكررة بلطف. استخدم مفتاح idempotency (مثل معرف الحدث) لإزالة التكرار.
- Exponential backoff: أعد المحاولة بعد تأخيرات متزايدة (مثل 1 ثانية، 5 ثوانٍ، 30 ثانية، 5 دقائق، 30 دقيقة) لإعطاء المستقبل وقتًا للتعافي.
- الحد الأقصى لإعادة المحاولة: قم بتعيين حد (مثل 5 محاولات) ثم ضع علامة على webhook كفاشل، وربما تنبيه المستخدم.
- المهلات: قم بتعيين مهلة معقولة (مثل 10 ثوانٍ) لكل محاولة.
تنفيذ إعادة المحاولة
يستخدم معظم مرسلي webhook نظام قائمة انتظار (مثل Redis أو RabbitMQ أو قاعدة بيانات) لجدولة إعادة المحاولة. إليك تدفقًا مبسطًا:
- عند تفعيل الحدث، ضع مهمة webhook في قائمة الانتظار مع الحمولة وعنوان URL الهدف.
- يأخذ العامل المهمة ويحاول التسليم.
- إذا كانت حالة الاستجابة 2xx، ضع علامة نجاح.
- إذا لم يكن كذلك، جدول إعادة محاولة مع exponential backoff، حتى الحد الأقصى للمحاولات.
- بعد الحد الأقصى للمحاولات، ضع علامة فشل وأبلغ.
مثال على جدول إعادة المحاولة:
| المحاولة | التأخير |
|---|---|
| 1 | فوري |
| 2 | دقيقة واحدة |
| 3 | 5 دقائق |
| 4 | 30 دقيقة |
| 5 | ساعتان |
أفضل الممارسات لأمان webhook
- استخدم HTTPS: قم دائمًا بتسليم webhooks عبر TLS لمنع التنصت.
- تدوير الأسرار: قم بتدوير الأسرار المشتركة بشكل دوري ودعم أسرار نشطة متعددة أثناء التدوير.
- التحقق من عناوين URL: تأكد من أن عنوان URL لـ webhook هو HTTPS وليس يشير إلى عناوين IP داخلية (لمنع SSRF).
- التسجيل والمراقبة: احتفظ بسجلات لمحاولات التسليم والفشل لتصحيح الأخطاء والتدقيق.
الأسئلة الشائعة
ما هي حمولة webhook الموقعة؟
تتضمن الحمولة الموقعة توقيعًا تشفيريًا (عادة HMAC) يسمح للمستقبل بالتحقق من أصالة المرسل وأن الحمولة لم يتم التلاعب بها.
كم مرة يجب أن أعيد محاولة webhook فاشل؟
لا توجد إجابة واحدة تناسب الجميع، ولكن النهج الشائع هو 3-5 محاولات إعادة مع exponential backoff. ضع في اعتبارك أهمية الحدث وقدرة المستقبل.
هل يمكنني استخدام JWT لتوقيعات webhook؟
نعم، يمكن استخدام JWT، لكنه أكثر تعقيدًا. HMAC أبسط وكافٍ لمعظم حالات الاستخدام. JWT مفيد إذا كنت بحاجة إلى تضمين مطالبات أو انتهاء صلاحية داخل التوقيع نفسه.
هل أنت مستعد لاختبار حمولات webhook الخاصة بك؟ استخدم JSON Formatter للتحقق من حمولات JSON الخاصة بك وتنسيقها بشكل جميل قبل الإرسال.