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 בשפות מסוימות.

איזה סוד?

אחסנו את הסוד במנהל הסודות או במשתנה הסביבה שלכם — לעולם אל תבצעו לו commit.

מימושי עזר

כל ארבעת המימושים מאמתים את גוף הבקשה הגולמי:

חיבור ספציפי למסגרת עבודה

אימות קריאות לכלים

כאשר הסוכן מפעיל ישירות אחד מ- כלי הפונקציות שלכם (לכלי יש 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.json() של Express צורכת את זרם הגוף ואתם מאבדים את הבתים הגולמיים. השתמשו ב-express.raw() במיוחד בנתיב ה-webhook, או אחסנו את הגוף הגולמי במאגר בתוכנת תווך מוקדמת. אותו הדבר נכון לגבי NestJS / Koa — עיינו בתיעוד שלהם בנושא “raw body”.
expected === signature ב-JS או expected == signature ב- Python הן השוואות שזמן הביצוע שלהן משתנה. השתמשו ב-crypto.timingSafeEqual או ב-hmac.compare_digest בהתאמה. ההבדל בביצועים זניח.
קריאות ישירות לנקודות קצה של כלים נחתמות באמצעות סוד ה-webhook ברמת הארגון (GET /v1/webhook) — ולא באמצעות סוד ספציפי לנקודת קצה מתוך /v1/developer/webhook-endpoints. השתמשו מחדש באותה פונקציית verify(), אך ודאו שאתם מעבירים לה את סוד הארגון בנתיבי כלים.
עבור שיטות כלים ללא גוף, החתימה מכסה את מחרוזת הבתים הריקה, וכך נשמר מתכון אוניברסלי אחד: הפעילו HMAC על גוף הבקשה הגולמי, יהיה אשר יהיה. גיבוב ה-URL או מחרוזת השאילתה לעולם לא יתאים.
החזרת 200 כאשר האימות נכשל הופכת את המטפל ליעד להתקפת שידור חוזר. החזירו תמיד תגובה שאינה 2xx אם האימות נכשל.

השלבים הבאים

סקירת webhooks

סמנטיקת מסירה, ניסיונות חוזרים, כתובות IP של המקור.

נקודות קצה של webhook

נהלו כמה כתובות URL, החליפו סודות.

כלי פונקציות

שני נתיבי הפעלת הכלים ומבני הבקשות שלהם.

שילובי כלים

בנו שילוב מלא המבוסס על כלים מקצה לקצה.