Skip to main content
كل طلب نرسله إلى خادمك — تسليمات webhook واستدعاءات نقاط نهاية الأدوات — يحمل توقيع HMAC-SHA256 في ترويسة X-ThunderPhone-Signature. نفّذ التحقق بشكل صحيح مرة واحدة وأدرج الدالة المساعدة نفسها في كل معالج.

الخوارزمية

  1. اقرأ نص الطلب الخام — البايتات الدقيقة التي أرسلناها إليك عبر POST.
  2. احسب hmac_sha256(secret, body).hexdigest().
  3. قارنه في وقت ثابت مع X-ThunderPhone-Signature. (تؤدي مقارنة السلاسل النصية البسيطة إلى كشف معلومات التوقيت.)
نوقّع البايتات التي نرسلها بدقة، لذا يعمل التحقق من النص الخام دائمًا. هذه البايتات هي أيضًا تسلسل JSON القياسي للحمولة — مفاتيح مرتبة أبجديًا، وفواصل مختصرة (, و : من دون مسافات)، وترميز UTF-8. يمنحك ذلك طريقة ثانية مكافئة تمامًا عندما لا يكشف إطار العمل لديك إلا JSON بعد تحليله: أعِد تسلسله بالشكل القياسي واحسب HMAC له.
فضّل النص الخام — فهو خطوة أقل ومحمي من مشكلات إعادة تحويل أرقام JSON في بعض اللغات.

أي سر؟

خزّن السر في مدير الأسرار أو متغير البيئة لديك — ولا تُضمّنه في المستودع مطلقًا.

عمليات تنفيذ مرجعية

تتحقق التطبيقات الأربعة جميعها من نص الطلب الخام:

التوصيل الخاص بإطار العمل

التحقق من استدعاءات الأدوات

عندما يستدعي الوكيل إحدى أدوات الدوال مباشرةً (تحتوي الأداة على endpoint)، يتضمن الطلب رأسي ThunderPhone التاليين إلى جانب endpoint.headers الذي أعددته:
  • X-ThunderPhone-Call-ID — المعرّف الرقمي للمكالمة المباشرة.
  • X-ThunderPhone-Signature — HMAC-SHA256، باستخدام سر webhook على مستوى المؤسسة، على بايتات نص الطلب الدقيقة.
تعمل دالة المساعدة verify() نفسها دون تغيير، مع اختلافين:
  1. لا تحتوي أدوات GET / DELETE على نص. تنتقل الوسائط كمعلمات استعلام، ويُحتسب التوقيع على سلسلة البايتات الفارغة — لذا استخدم verify(b"", sig, secret) ‏(Python) أو verify(Buffer.alloc(0), sig, secret) ‏(Node). لا تُجزّئ سلسلة الاستعلام.
  2. المؤسسات التي ليس لديها webhook قديم مُعدّ لا تملك سر مؤسسة. في هذه الحالة، لا تتضمن استدعاءات الأدوات سوى X-ThunderPhone-Call-ID ولا تتضمن رأس توقيع. أعدّ webhook القديم (PUT /v1/webhook) للحصول على سر توقيع، أو صادق استدعاءات الأدوات باستخدام رأسك الخاص عبر endpoint.headers.
إن إرسال الأدوات في وضع webhook (الأدوات التي لا تحتوي على endpoint، وتُسلَّم إلى webhook مؤسستك بصيغة telephony.tool / web.tool) هو webhook عادي موقّع — تنطبق الوصفة القياسية أعلاه. راجع أدوات الدوال لكلا شكلي الطلب.

الأخطاء الشائعة

يؤدي تحليل النص وإعادة تفريغه باستخدام الإعدادات الافتراضية لمكتبة JSON (مسافات بعد , / :، ومفاتيح مرتبة حسب الإدراج) إلى إنتاج بايتات مختلفة وكسر HMAC. تحقّق من النص الخام — أو إذا اضطررت إلى إعادة التسلسل، فطابق صيغتنا القياسية تمامًا: مفاتيح مرتبة، وفواصل مضغوطة، وترميز UTF-8.
تستهلك برمجية Express الوسيطة express.json() تدفق النص وتفقد البايتات الخام. استخدم express.raw() تحديدًا على مسار الويبهوك، أو خزّن النص الخام مؤقتًا في برمجية وسيطة مسبقة. وينطبق الأمر نفسه على NestJS / Koa — راجع وثائقهما حول “النص الخام”.
تمثل expected === signature في JS أو expected == signature في Python مقارنات يتغير توقيتها. استخدم crypto.timingSafeEqual أو hmac.compare_digest على التوالي. فرق الأداء معدوم.
تُوقَّع استدعاءات نقاط نهاية الأدوات المباشرة باستخدام سر الويبهوك على مستوى المؤسسة (GET /v1/webhook) — وليس باستخدام أي سر لكل نقطة نهاية من /v1/developer/webhook-endpoints. أعد استخدام دالة verify() نفسها، لكن تأكد من تمرير سر المؤسسة إليها في مسارات الأدوات.
بالنسبة إلى أساليب الأدوات التي لا تحتوي على نص، يغطي التوقيع سلسلة البايتات الفارغة، مما يحافظ على وصفة عامة واحدة: طبّق HMAC على نص الطلب الخام، مهما كان. لن تتطابق تجزئة عنوان URL أو سلسلة الاستعلام أبدًا.
يؤدي إرجاع 200 عند فشل التحقق إلى جعل المعالج هدفًا لإعادة الإرسال. أعد دائمًا استجابة غير 2xx إذا فشل التحقق.

الخطوات التالية

نظرة عامة على الويبهوكات

دلالات التسليم، وإعادات المحاولة، وعناوين IP المصدر.

نقاط نهاية الويبهوك

أدر عناوين URL متعددة، ودوّر الأسرار.

أدوات الدوال

مسارا استدعاء الأدوات وأشكال طلباتهما.

تكاملات الأدوات

أنشئ تكاملًا كاملًا مدعومًا بأداة من البداية إلى النهاية.