شرح Webhooks: الحمولات الموقعة وإعادة المحاولات

Backend2026-10-14TryQuickToolBox

لماذا تعتبر Webhooks صعبة؟

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

تستعرض هذه المقالة الجانبين الأكثر أهمية لـ webhooks الجاهزة للإنتاج: الحمولات الموقعة وإعادة المحاولات. سنغطي كيفية التحقق من التوقيعات، وكيفية تنفيذ إعادة المحاولات مع التراجع الأسي، وكيفية جعل المعالجة الخاصة بك متكررة آمنة.

الحمولات الموقعة: إثبات الأصالة

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

يستخدم معظم المزودين HMAC-SHA256. عادةً ما يتم حساب التوقيع على جسم الطلب الخام (أحيانًا مع طابع زمني) وترميزه بنظام hex. على سبيل المثال، يستخدم Stripe ترويسة مثل Stripe-Signature تحتوي على طابع زمني وتوقيع.

كيف يعمل HMAC

HMAC (رمز المصادقة على الرسائل المعتمد على التجزئة) يجمع بين مفتاح سري ودالة تجزئة. بالنظر إلى نفس المفتاح والرسالة، يكون الناتج حتميًا. بدون المفتاح، لا يمكن للمهاجم تزوير توقيع صالح.

إليك مثالاً بسيطًا في Node.js:

const crypto = require('crypto');

function verifySignature(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

في Python، الأمر بنفس البساطة:

import hmac
import hashlib

def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

أفضل الممارسات للتحقق من التوقيع

التعامل مع الطوابع الزمنية وهجمات إعادة التشغيل

يتضمن العديد من المزودين طابعًا زمنيًا في ترويسة التوقيع. على سبيل المثال، قد تكون الترويسة t=1614556800,v1=abc123.... يجب عليك:

  1. استخراج الطابع الزمني والتوقيع.
  2. التحقق من أن الطابع الزمني ضمن نافذة مقبولة (مثلاً 5 دقائق).
  3. إعادة حساب التوقيع باستخدام الطابع الزمني والحمولة.
  4. مقارنة التوقيعات بشكل آمن.

هذا يمنع المهاجم من إعادة تشغيل طلب صالح قديم.

إعادة المحاولات: التعامل مع الأعطال بلطف

يتم تسليم Webhooks عبر الإنترنت العام، لذا فإن الأعطال حتمية. قد تكون نقطة النهاية الخاصة بك معطلة، أو بطيئة، أو ترجع خطأ 500. سيقوم المزود القوي بإعادة محاولة عمليات التسليم الفاشلة، لكنك أيضًا بحاجة إلى التعامل مع إعادة المحاولات من جانبك إذا كنت أنت المزود.

التراجع الأسي مع العشوائية

عند إعادة المحاولة، تجنب قصف نقطة النهاية بإعادة محاولات فورية. استخدم التراجع الأسي: انتظر لفترة أطول بعد كل فشل. أضف العشوائية (jitter) لتجنب مشاكل القطيع المتدافع عندما تفشل العديد من webhooks في وقت واحد.

قد يبدو جدول إعادة المحاولة النموذجي كالتالي:

المحاولةالتأخير (تقريبي)
1فوري
230 ثانية
35 دقائق
430 دقيقة
5ساعتان

بعد الحد الأقصى لعدد المحاولات، ضع علامة على التسليم كفاشل وقم بالتنبيه.

ضمان التنفيذ المتكرر الآمن: مفتاح إعادة المحاولات الآمنة

لأن إعادة المحاولات يمكن أن تسبب عمليات تسليم مكررة، يجب أن يكون معالج webhook الخاص بك متكررًا آمنًا. وهذا يعني أن معالجة نفس الحدث عدة مرات يجب أن يكون لها نفس تأثير معالجته مرة واحدة.

كيفية تحقيق التنفيذ المتكرر الآمن:

تنفيذ إعادة المحاولات على جانب المزود

إذا كنت تبني نظام webhook، فأنت بحاجة إلى آلية تسليم موثوقة. إليك نهجًا مبسطًا:

  1. عندما يحدث حدث، ضع مهمة تسليم في قائمة الانتظار مع الحمولة وعنوان URL الهدف.
  2. يأخذ عامل المهمة ويرسل HTTP POST مع مهلة (مثلاً 10 ثوانٍ).
  3. إذا كانت حالة الاستجابة ليست 2xx، جدول إعادة محاولة مع التراجع الأسي.
  4. تتبع المحاولات واستسلم بعد حد أقصى (مثلاً 5 محاولات).
  5. سجّل الأعطال ووفر طريقة للمستخدمين لإعادة التشغيل يدويًا.

استخدم قائمة انتظار دائمة (مثل Redis أو RabbitMQ أو جدول قاعدة بيانات) حتى تنجو إعادة المحاولات من عمليات إعادة التشغيل.

تجميع كل شيء: قائمة تحقق لمستقبل Webhook

عند بناء مستقبل webhook، اتبع قائمة التحقق هذه:

الأسئلة الشائعة

ما هي حمولة webhook الموقعة؟

تتضمن الحمولة الموقعة توقيعًا تشفيريًا (عادةً HMAC-SHA256) يتم إنشاؤه باستخدام سر مشترك. يعيد المستقبل حساب التوقيع للتحقق من أن الطلب جاء من المرسل المتوقع ولم يتم العبث به.

لماذا تحتاج webhooks إلى إعادة المحاولات؟

يمكن أن تؤدي مشاكل الشبكة أو تعطل الخادم أو الأخطاء المؤقتة إلى فشل تسليم webhook. تضمن إعادة المحاولات مع التراجع الأسي تسليم الحدث في النهاية دون إرهاق المستقبل.

كيف أمنع معالجة webhook المكررة؟

استخدم التنفيذ المتكرر الآمن: ضمّن معرف حدث فريد في الحمولة، وخزّن المعرفات المعالجة، وصمم عملياتك لتكون متكررة آمنة (مثل upserts). بهذه الطريقة، حتى إذا تم تسليم webhook عدة مرات، يكون التأثير نفسه.

إذا كنت بحاجة إلى فحص أو تصحيح حمولات webhook، يمكن أن يساعدك JSON Formatter في تنسيق بيانات JSON والتحقق منها بسرعة.