Skip to main content
Każde żądanie, które wysyłamy na Twój serwer — dostarczenie webhooka i wywołanie endpointu narzędzia — zawiera podpis HMAC-SHA256 w nagłówku X-ThunderPhone-Signature. Poprawnie zaimplementuj weryfikację raz, a następnie użyj tego samego pomocnika w każdym handlerze.

Algorytm

  1. Odczytaj surowe ciało żądania — dokładne bajty, które wysłaliśmy.
  2. Oblicz hmac_sha256(secret, body).hexdigest().
  3. Porównaj w stałym czasie z X-ThunderPhone-Signature. (Naiwne porównanie ciągów ujawnia informacje o czasie.)
Podpisujemy dokładnie te bajty, które przesyłamy, więc weryfikacja surowego ciała zawsze działa. Te bajty są również kanoniczną serializacją JSON payloadu — klucze posortowane alfabetycznie, zwarte separatory (, i : bez spacji), UTF-8. Daje to drugi, w pełni równoważny sposób, gdy framework udostępnia wyłącznie sparsowany JSON: ponownie serializuj kanonicznie i oblicz HMAC dla wyniku.
Preferuj surowe ciało — to o jeden krok mniej i nie jest podatne na problemy z ponownym przetwarzaniem liczb JSON w niektórych językach.

Który sekret?

Przechowuj sekret w menedżerze sekretów lub zmiennej środowiskowej — nigdy nie commituj go.

Implementacje referencyjne

Wszystkie cztery weryfikują surowe ciało żądania:

Integracja specyficzna dla frameworka

Weryfikowanie wywołań narzędzi

Gdy agent wywołuje bezpośrednio jedno z Twoich narzędzi funkcyjnych (narzędzie ma endpoint), żądanie zawiera dwa nagłówki ThunderPhone wraz z skonfigurowanymi przez Ciebie nagłówkami endpoint.headers:
  • X-ThunderPhone-Call-ID — numeryczny identyfikator trwającego połączenia.
  • X-ThunderPhone-Signature — HMAC-SHA256 z kluczem w postaci sekretu webhooka na poziomie organizacji, obliczony na podstawie dokładnych bajtów treści żądania.
Ten sam pomocnik verify() działa bez zmian, z dwoma niuansami:
  1. Narzędzia GET / DELETE nie mają treści. Argumenty są przekazywane jako parametry zapytania, a podpis jest obliczany na podstawie pustego ciągu bajtów — więc użyj verify(b"", sig, secret) (Python) lub verify(Buffer.alloc(0), sig, secret) (Node). Nie haszuj ciągu zapytania.
  2. Organizacje bez skonfigurowanego starszego webhooka nie mają sekretu organizacji. W takim przypadku wywołania narzędzi zawierają tylko X-ThunderPhone-Call-ID i nie zawierają nagłówka podpisu. Skonfiguruj starszy webhook (PUT /v1/webhook), aby uzyskać sekret podpisywania, lub uwierzytelniaj wywołania narzędzi własnym nagłówkiem za pomocą endpoint.headers.
Wysyłanie narzędzi w trybie webhooka (narzędzia bez endpoint, dostarczane do webhooka organizacji jako telephony.tool / web.tool) jest zwykłym podpisanym webhookiem — obowiązuje standardowa procedura opisana powyżej. Zobacz Narzędzia funkcyjne, aby poznać oba formaty żądań.

Typowe pułapki

Przetworzenie treści i ponowne zapisanie jej za pomocą biblioteki JSON z ustawieniami domyślnymi (spacje po , / :, klucze w kolejności wstawiania) powoduje powstanie innych bajtów i unieważnia HMAC. Zweryfikuj surową treść — lub jeśli musisz ją ponownie serializować, dokładnie dopasuj naszą formę kanoniczną: posortowane klucze, zwarte separatory, UTF-8.
Middleware express.json() w Express zużywa strumień treści i tracisz surowe bajty. Użyj express.raw() konkretnie dla trasy webhooka albo buforuj surową treść w pre-middleware. Tak samo jest w NestJS / Koa — sprawdź ich dokumentację dotyczącą „raw body”.
expected === signature w JS lub expected == signature w Pythonie to porównania o zmiennym czasie wykonania. Użyj odpowiednio crypto.timingSafeEqual lub hmac.compare_digest. Różnica w wydajności jest pomijalna.
Bezpośrednie wywołania endpointów narzędzi są podpisywane za pomocą sekretu webhooka na poziomie organizacji (GET /v1/webhook) — a nie za pomocą sekretu przypisanego do endpointu z /v1/developer/webhook-endpoints. Użyj ponownie tej samej funkcji verify(), ale upewnij się, że dla tras narzędzi przekazujesz do niej sekret organizacji.
W przypadku metod narzędzi bez treści podpis obejmuje pusty ciąg bajtów, co pozwala zachować jedną uniwersalną metodę: wykonaj HMAC na surowej treści żądania, niezależnie od tego, jaka ona jest. Haszowanie adresu URL lub ciągu zapytania nigdy nie będzie zgodne.
Zwracanie 200 po nieudanej weryfikacji sprawia, że handler staje się celem ataków typu replay. Zawsze zwracaj kod inny niż 2xx, jeśli weryfikacja się nie powiedzie.

Kolejne kroki

Przegląd webhooków

Semantyka dostarczania, ponowienia, źródłowe adresy IP.

Endpointy webhooków

Zarządzaj wieloma adresami URL, rotuj sekrety.

Narzędzia funkcji

Dwie ścieżki wywoływania narzędzi i formaty ich żądań.

Integracje narzędzi

Utwórz kompletną integrację opartą na narzędziach od początku do końca.