شرح Webhooks: البيانات الموقعة واستراتيجيات إعادة المحاولة
لقد قمت للتو ببناء نقطة نهاية webhook لتلقي الأحداث من خدمة طرف ثالث. كل شيء يعمل في الاختبار، ولكن في الإنتاج تلاحظ أن بعض الأحداث لا تصل أبدًا، أو الأسوأ من ذلك، تتلقى أحداثًا مكررة تسبب تناقضات في البيانات. هذه هي المزالق الكلاسيكية لـ webhooks التي تنبع من جانبين حاسمين: أصالة الحمولة وموثوقية التسليم.
Webhooks هي عمليات استدعاء HTTP يتم تشغيلها بواسطة الأحداث، ودفع البيانات إلى تطبيقك في الوقت الفعلي. على عكس الاستقصاء، فهي فعالة وفورية تقريبًا. لكنها تقدم تحديات: كيف تعرف أن الطلب جاء حقًا من المرسل المتوقع، وكيف تتعامل مع حالات الفشل عندما يكون المستقبل معطلاً مؤقتًا؟ يتعمق هذا المقال في البيانات الموقعة وآليات إعادة المحاولة، مما يمنحك أنماطًا عملية لبناء تكاملات webhook مرنة.
لماذا تحتاج Webhooks إلى توقيعات
نقاط نهاية webhook هي عناوين URL متاحة للجمهور. بدون التحقق، يمكن لأي شخص إرسال طلبات مزورة إلى نقطة النهاية الخاصة بك، مما قد يؤدي إلى إجراءات غير مصرح بها أو تلف البيانات. تحل البيانات الموقعة هذه المشكلة عن طريق إضافة توقيع تشفيري إلى كل طلب، مما يسمح لك بالتحقق من هوية المرسل والتأكد من عدم التلاعب بالحمولة.
يستخدم معظم المزودين HMAC (رمز مصادقة الرسائل القائم على التجزئة) مع سر مشترك. يحسب المرسل تجزئة للحمولة باستخدام السر ويضمّنها في رأس. تقوم بإعادة حساب التجزئة من جانبك ومقارنتها. إذا تطابقت، فإن الطلب شرعي.
تنفيذ التحقق من HMAC
لنستعرض تنفيذًا نموذجيًا في Node.js. افترض أن المزود يرسل توقيعًا في رأس X-Signature، محسوبًا كـ HMAC-SHA256 لجسم الطلب الخام باستخدام السر الخاص بك.
const crypto = require('crypto');
const express = require('express');
const app = express();
// Use raw body parser to preserve exact payload
app.use(express.raw({ type: 'application/json' }));
app.post('/webhook', (req, res) => {
const signature = req.headers['x-signature'];
const secret = process.env.WEBHOOK_SECRET;
const expected = crypto
.createHmac('sha256', secret)
.update(req.body)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
return res.status(401).send('Invalid signature');
}
// Process the event
const event = JSON.parse(req.body);
// ... handle event
res.status(200).send('OK');
});
نقاط رئيسية:
- استخدم دائمًا جسم الطلب الخام للتحقق، وليس JSON المحلل. يمكن أن يؤدي التحليل إلى تغيير المسافات البيضاء أو ترتيب المفاتيح، مما يكسر التجزئة.
- استخدم مقارنة آمنة زمنيًا لمنع هجمات التوقيت.
- احتفظ بسرك آمنًا؛ قم بتدويره بشكل دوري ودعم أسرار متعددة نشطة أثناء التدوير.
تصميم استراتيجية إعادة المحاولة
حتى مع التوقيعات، يمكن أن تفشل عمليات التسليم بسبب مشكلات الشبكة أو تعطل الخادم أو المهلات. تضمن استراتيجية إعادة المحاولة القوية التسليم النهائي دون إرهاق نظامك أو المرسل.
1. أقر بسرعة، وعالج بشكل غير متزامن
يجب أن تستجيب نقطة نهاية webhook الخاصة بك بحالة 2xx في أسرع وقت ممكن، ويفضل في غضون ثوانٍ قليلة. إذا استغرق المعالجة وقتًا أطول، فضع الحدث في قائمة انتظار للمعالجة في الخلفية. هذا يمنع المهلات ويسمح للمرسل باعتبار التسليم ناجحًا.
2. تنفيذ التراجع الأسي مع التذبذب
عند فشل التسليم (استجابة غير 2xx أو مهلة)، يجب على المرسل إعادة المحاولة بتأخيرات متزايدة. يمنع التراجع الأسي (مثل 1 ثانية، 2 ثانية، 4 ثوانٍ، 8 ثوانٍ...) إرهاق نقطة النهاية الخاصة بك. إضافة تذبذب عشوائي يتجنب مشاكل القطيع المتلاطم عندما تفشل العديد من webhooks في وقت واحد.
مثال على جدول إعادة المحاولة:
- المحاولة 1: فورية
- المحاولة 2: بعد 30 ثانية
- المحاولة 3: بعد دقيقتين
- المحاولة 4: بعد 10 دقائق
- المحاولة 5: بعد ساعة
بعد الحد الأقصى لعدد مرات إعادة المحاولة (مثل 5)، يجب على المرسل التوقف وإخطارك (على سبيل المثال، عبر البريد الإلكتروني أو لوحة التحكم).
3. التعامل مع التكرارات باستخدام Idempotency
يمكن أن تسبب إعادة المحاولة عمليات تسليم مكررة. يجب أن تكون نقطة النهاية الخاصة بك متسقة (idempotent): معالجة نفس الحدث عدة مرات يجب أن يكون لها نفس تأثير معالجته مرة واحدة. استخدم معرف حدث فريد من الحمولة وقم بتخزينه. قبل المعالجة، تحقق مما إذا كان المعرف قد تم رؤيته؛ إذا كان الأمر كذلك، فأعد 200 دون إعادة المعالجة.
الأساليب الشائعة:
- قيد فريد في قاعدة البيانات على معرف الحدث.
- مجموعة Redis مع TTL للمعرفات التي تمت معالجتها مؤخرًا.
- مفاتيح Idempotency في منطق عملك.
مقارنة: البيانات الموقعة مقابل إجراءات الأمان الأخرى
| الطريقة | الإيجابيات | السلبيات |
|---|---|---|
| توقيع HMAC | يتحقق من الأصالة والسلامة؛ عديم الحالة | يتطلب إدارة سر مشترك |
| قائمة IP المسموح بها | سهل التنفيذ | يمكن أن تتغير عناوين IP؛ غير مناسب للبيئات الديناميكية |
| المصادقة الأساسية | سهل الإضافة | يتم إرسال بيانات الاعتماد في كل طلب؛ أقل أمانًا |
| JWT في الرأس | يمكن أن يشمل المطالبات وانتهاء الصلاحية | عبء إصدار/التحقق من الرمز المميز |
توقيعات HMAC هي المعيار الفعلي لأنها عديمة الحالة وفعالة وتوفر أمانًا قويًا عند تنفيذها بشكل صحيح.
أفضل الممارسات لمستهلكي Webhook
- تحقق من التوقيعات في كل طلب، حتى في التطوير.
- استجب بسرعة؛ قم بتفريغ المعالجة الثقيلة إلى قائمة انتظار.
- سجل كل شيء — الرؤوس والحمولة ونتيجة المعالجة — لتصحيح الأخطاء.
- راقب حالات الفشل وقم بإعداد تنبيهات للأخطاء المتكررة.
- استخدم HTTPS لحماية الحمولات أثناء النقل.
- قم بتدوير الأسرار بانتظام ودعم أسرار متعددة نشطة أثناء التدوير.
أفضل الممارسات لمنتجي Webhook
- وقع الحمولات باستخدام سر فريد لكل مستهلك.
- قم بتضمين معرف حدث فريد للمساعدة في Idempotency.
- أعد المحاولة مع التراجع وحدد عدد المحاولات.
- وفر لوحة تحكم للمستهلكين لعرض سجلات التسليم وإعادة تشغيل الأحداث.
- وثق نظام التوقيع الخاص بك بوضوح.
اختبار تنفيذ Webhook الخاص بك
استخدم أدوات مثل ngrok لكشف خادمك المحلي ومحاكاة عمليات تسليم webhook. اكتب اختبارات وحدة للتحقق من التوقيع ومنطق Idempotency. لاختبار الحمل، فكر في الأدوات التي يمكنها إرسال طلبات موقعة على نطاق واسع.
عند تصحيح الأخطاء، افحص الحمولة الخام والرؤوس. يمكن أن يساعد منسق JSON في تصور بنية الحمولة. جرب منسق JSON الخاص بنا لطباعة وتنسيق والتحقق من حمولات webhook بسرعة.
الأسئلة الشائعة
ما هي حمولة webhook الموقعة؟
تتضمن الحمولة الموقعة توقيعًا تشفيريًا (عادة HMAC) يسمح للمستقبل بالتحقق من هوية المرسل والتأكد من عدم تغيير الحمولة. يتم حسابه باستخدام سر مشترك وجسم الطلب.
كم مرة يجب إعادة محاولة webhook؟
لا يوجد رقم عالمي، لكن الممارسة الشائعة هي 3-5 مرات إعادة محاولة مع التراجع الأسي. بعد ذلك، يعتبر الحدث فاشلاً ويجب إخطار المستهلك للتحقيق أو إعادة التشغيل يدويًا.
هل يمكنني استخدام JWT بدلاً من HMAC لتوقيعات webhook؟
نعم، يمكن أن يعمل JWT، لكنه يضيف تعقيدًا (إصدار الرمز المميز، انتهاء الصلاحية). HMAC أبسط وكافٍ لمعظم حالات الاستخدام. اختر بناءً على البنية التحتية والمتطلبات الحالية.
هل أنت مستعد لفحص وتصحيح حمولات webhook؟ استخدم منسق JSON المجاني الخاص بنا لتنسيق والتحقق من JSON على الفور.