مركز إدارة النفايات الصلبة كيف تعرف ويب هوكات أنك لم تكذب

نُشرت في

كلما أرسل GitHub أو Stripe أو Shopify إشعارًا (webhook) إلى خادمك، يُوقِّع الطرف (payload) باستخدام HMAC. إليك كيف يعمل هذا - وكيف يمكنك التحقق منه في كودك الخاص.

HMAC: كيف تعرف أنك لم تكذب في ويب هوكات 1
إعلان · حذف؟

تتلقى طلبًا POST يدعي أنه من ستريب. يشير المحتوى إلى أن دفعة تمت بنجاح. تُعالج الطلب، وتُرسل البضائع - وثلاثة أيام لاحقًا تكتشف أن الطلب تم تزييفه. ألم.

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

ما هو HMAC بالفعل

HMAC تعني كود تحقق الرسالة القائم على التجزئة. يجيب على سؤال واحد: "هل كان الشخص الذي أرسل لي الرسالة يمتلك السر المشترك؟"

يعمل من خلال تطبيق دالة تجزئة تشفيرية - عادةً SHA-256 - على تجميع مفتاح سري وجسم الرسالة. الناتج هو سلسلة من الطول الثابت التي:

  • تتغير تمامًا إذا تغيرت أي وحدة من الرسالة
  • لا يمكن إنتاجها بدون معرفة مفتاح السر
  • لا يمكن عكسها لإظهار المفتاح أو الرسالة الأصلية

الصيغة مختصرة: HMAC(key, message) = H((key ⊕ opad) || H((key ⊕ ipad) || message)). لا تحتاج إلى تذكر التفاصيل الداخلية - كل لغة تمتلك تطبيقًا معياريًا - لكن من المفيد أن تعرف الغرض: يتم دمج المفتاح في التجزئة مرتين بطرق مختلفة لمنع نوع من الهجمات يُعرف بـ "هجمات التمديد"

كيف يستخدم مزود ويب هوك هذا

عند تسجيل نقطة ويب هوك، يُعطى لك مفتاح التوقيع - سلسلة عشوائية تعرفها فقط أنت وهم. عند حدوث حدث:

  1. يُحوّل مزود الحدث المحتوى إلى صيغة JSON (أو سلسلة معيارية).
  2. يُحسب HMAC-SHA256(secret, payload).
  3. يُرسل الطلب مع التوقيع في رأس الطلب - X-Hub-Signature-256 لجيثوب، Stripe-Signature لستريب، وما إلى ذلك.

من جانبك، تُجرى عملية الحساب نفسها على جسم الطلب الأصلي وتحاول مقارنته. إذا كانت متطابقة، فالمحتوى موثوق. وإذا لم تكن، ارفضه.

التحقق من الكود

إليك ما يشبهه التحقق في اللغات الأكثر شيوعًا. النمط متماثل في كل لغة: حساب، مقارنة باستخدام دالة بوقت ثابت.

نود.جي اس

const crypto = require('crypto');

function verifyWebhook(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)          // rawBody must be a Buffer or string — NOT parsed JSON
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

بايثون

import hmac
import hashlib

def verify_webhook(raw_body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        raw_body,
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(expected, signature)

PHP

function verifyWebhook(string $rawBody, string $signature, string $secret): bool {
    $expected = hash_hmac('sha256', $rawBody, $secret);
    return hash_equals($expected, $signature);
}

التفاصيل المهمة: استخدام الجسم الأصلي

أكبر خطأ في التنفيذ الشائع هو إرسال محتوى مُحلّل ومُعاد تسلسله إلى دالة HMAC بدلًا من الأحرف الخام. تأثير ترتيب المفتاح، المسافات، وتحويلات Unicode يُؤثر على التجزئة. وقد وقّع المزود على الأحرف الخام التي أرسلها - يجب أن تجزئ نفس هذه الأحرف.

في إكسبريس (نود جس)، يعني ذلك تكوين مُعالج جسم الطلب لحفظ البيانات الخام:

app.use('/webhooks', express.raw({ type: 'application/json' }));

في داينو، استخدم request.body بدلاً من request.data. في فلسك، استخدم request.get_data().

لماذا لا تستخدم تجزئة بسيطة؟

تجزئة بسيطة من نوع SHA-256 لا تُثبت أي شيء - يمكن لأي شخص حساب SHA256(payload) بدون سر. مفتاح HMAC هو ما يجعله المصادقة كودًا، وليس مجرد ملخص. يجيب على "من أرسل هذا" بدلًا من "هل تم تلفه أثناء النقل؟"

لماذا لا تستخدم التوقيعات غير المتماثلة (مثل RSA)؟

تتيح RSA وECDSA للمرسل التحقق من التوقيع دون معرفة المفتاح الخاص - وهذا مفيد للنشر العام (مثل التوقيع على الكود). بالنسبة للويب هوكات، هناك فقط طرفان يرغبان في التحقق من التوقيع: أنت ومزود الخدمة. المفتاح المشترك أبسط، أسرع، وآمن بنفس الدرجة في هذا النموذج. بعض المزودين (Svix، Clerk) يقدّمون التوقيع غير المتماثل للويب هوكات لحالات لا يمكن فيها تخزين سر على الخادم.

هجمات التكرار - وكيف تمنعها

توقيع HMAC الموثوق يثبت صحة الرسالة لكنه لا يضمن أنها حديثة. يمكن للاختراق أن يُعيد إرسال طلب موثوق لاحقًا. تُستخدم ستريب هذه الطريقة من خلال إدراج وقت في Stripe-Signature الرأس وتقسيم القيمة مع جسم الرسالة. من جانبك، ترفض أي طلب يحتوي على وقت أقدم من خمسة دقائق.

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

المقارنة الزمنية الآمنة ليست اختيارية

لا تقارن توقيعات HMAC باستخدام مقارنة بسيطة (===, ==). تدفق المقارنة السطحي يُكشف عن معلومات حول عدد الحروف المطابقة من البداية - يمكن للاختراق الذي يرسل آلاف الطلبات إعادة بناء التوقيع بحروف واحدة على حدة. استخدم دائمًا مقارنة بوقت ثابت:

  • نودي جي: crypto.timingSafeEqual()
  • بايثون: hmac.compare_digest()
  • PHP: hash_equals()
  • Go: hmac.Equal()
  • Ruby: ActiveSupport::SecurityUtils.secure_compare()

الجمع: مثال على مُعالج ويب هوك جاهز للإنتاج

إليك مثالًا كاملًا باستخدام رأس X-Hub-Signature-256 التوقيع

const express = require('express');
const crypto = require('crypto');

const app = express();
const WEBHOOK_SECRET = process.env.GITHUB_WEBHOOK_SECRET;

// Keep the body as raw bytes — critical!
app.use('/github/webhook', express.raw({ type: 'application/json' }));

app.post('/github/webhook', (req, res) => {
  const sigHeader = req.headers['x-hub-signature-256'];
  if (!sigHeader) return res.status(401).send('Missing signature');

  const sig = sigHeader.replace('sha256=', '');
  const expected = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(req.body)
    .digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig))) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(req.body);
  // Safe to process the event now
  console.log('Event type:', req.headers['x-github-event']);

  res.sendStatus(200);
});

app.listen(3000);

المرجع السريع: من يُستخدم ماذا

المزودرأس الصفحةالخوارزميةالوقت في التوقيع؟
جيثبX-Hub-Signature-256HMAC-SHA256لا
StripeStripe-SignatureHMAC-SHA256نعم
ShopifyX-Shopify-Hmac-Sha256HMAC-SHA256لا
TwilioX-Twilio-SignatureHMAC-SHA1لا
الركودX-Slack-SignatureHMAC-SHA256نعم
PaddlePaddle-SignatureHMAC-SHA256نعم
هل تريد حذف الإعلانات؟ تخلص من الإعلانات اليوم

تثبيت ملحقاتنا

أضف أدوات IO إلى متصفحك المفضل للوصول الفوري والبحث بشكل أسرع

أضف لـ إضافة كروم أضف لـ امتداد الحافة أضف لـ إضافة فايرفوكس أضف لـ ملحق الأوبرا

وصلت لوحة النتائج!

لوحة النتائج هي طريقة ممتعة لتتبع ألعابك، يتم تخزين جميع البيانات في متصفحك. المزيد من الميزات قريبا!

إعلان · حذف؟
إعلان · حذف؟
إعلان · حذف؟

ركن الأخبار مع أبرز التقنيات

شارك

ساعدنا على الاستمرار في تقديم أدوات مجانية قيمة

اشتري لي قهوة
إعلان · حذف؟