Open in
வெப்ஹுக் கையொப்பங்களைச் சரிபார்க்கவும்
ThunderPhone அனுப்பும் ஒவ்வொரு வெப்ஹுக் மற்றும் கருவி கோரிக்கையும் கையொப்பமிடப்பட்டிருக்கும். இங்குள்ள முறையைப் பயன்படுத்தி கையொப்பத்தை ஒருமுறை சரிபார்க்கவும்; பின்னர் நீங்கள் இயக்கும் ஒவ்வொரு எண்ட்பாயிண்ட்டிலும் அதே சரிபார்ப்பை மீண்டும் பயன்படுத்தவும்.
உங்கள் சர்வருக்கு நாங்கள் அனுப்பும் ஒவ்வொரு கோரிக்கையிலும் — வெப்ஹுக் டெலிவரிகள் மற்றும்
கருவி-எண்ட்பாயிண்ட் அழைப்புகள் — X-ThunderPhone-Signature ஹெடரில் ஒரு HMAC-SHA256 கையொப்பம் இருக்கும். சரிபார்ப்பை ஒருமுறை சரியாக அமைத்து,
அதே உதவியாளரை ஒவ்வொரு ஹேண்ட்லரிலும் பயன்படுத்துங்கள்.
அல்காரிதம்
- மூல கோரிக்கை உடலைப் படியுங்கள் — நாங்கள் உங்களுக்கு POST செய்த துல்லியமான பைட்கள்.
hmac_sha256(secret, body).hexdigest()-ஐ கணக்கிடுங்கள்.X-ThunderPhone-Signatureஉடன் நிலையான நேரத்தில் ஒப்பிடுங்கள். (எளிய சரம் ஒப்பீடு நேரத் தகவலை வெளிப்படுத்தும்.)
நாங்கள் அனுப்பும் துல்லியமான பைட்களிலேயே கையொப்பமிடுகிறோம், எனவே மூல உடலை
சரிபார்ப்பது எப்போதும் செயல்படும். அந்த பைட்கள் பேலோடின் நியமமான JSON தொடராக்கமும்
ஆகும் — விசைகள் அகரவரிசையில் வரிசைப்படுத்தப்பட்டு, சுருக்கமான பிரிப்பான்களுடன்
(இடைவெளிகளின்றி , மற்றும் :), UTF-8. உங்கள் ஃப்ரேம்வொர்க் பாகுபடுத்தப்பட்ட JSON-ஐ மட்டுமே வழங்கும்போது, இதனால்
முழுமையாகச் சமமான இரண்டாவது முறையும் கிடைக்கும்:
நியமமாக மீண்டும் தொடராக்கி, அதற்கு HMAC செய்யுங்கள்.
# Equivalent to hashing the raw body:
import json
canonical = json.dumps(payload, separators=(",", ":"), sort_keys=True).encode("utf-8")மூல உடலையே முன்னுரிமையாகப் பயன்படுத்துங்கள் — அது ஒரு படி குறைவானது; சில மொழிகளில் JSON எண்களை மீண்டும் மாற்றும் நுணுக்கங்களிலிருந்தும் பாதுகாப்பானது.
எந்த ரகசியம்?
| மூலம் | ரகசியம் |
|---|---|
வெப்ஹுக் எண்ட்பாயிண்ட் (/v1/developer/webhook-endpoints) | உருவாக்கும்போது ஒருமுறை வழங்கப்படும் எண்ட்பாயிண்ட்-ஒன்றுக்கான secret (48 ஹெக்ஸ் எழுத்துகள்) |
| பழைய ஒற்றை-URL வெப்ஹுக் | GET /v1/webhook-இல் வழங்கப்படும் நிறுவனம்-ஒன்றுக்கான secret |
கருவி-எண்ட்பாயிண்ட் அழைப்பு (உங்கள் endpoint.url-க்கு நேரடி அழைப்பு) | நிறுவன-நிலை வெப்ஹுக் ரகசியம் (பழைய ஒற்றை-URL வெப்ஹுக்கில் உள்ளதே) — எண்ட்பாயிண்ட்-ஒன்றுக்கான ரகசியம் அல்ல |
ரகசியத்தை உங்கள் ரகசிய மேலாளர் அல்லது env மாறியில் சேமியுங்கள் — அதை ஒருபோதும் கமிட் செய்யாதீர்கள்.
குறிப்பு செயலாக்கங்கள்
நான்கும் மூல கோரிக்கை உடலைச் சரிபார்க்கின்றன:
import hashlib
import hmac
def verify(body: bytes, signature: str, secret: str) -> bool:
"""Constant-time HMAC-SHA256 verification."""
expected = hmac.new(
secret.encode("utf-8"),
body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, signature or "")import crypto from "node:crypto";
export function verify(body, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(body)
.digest("hex");
if (!signature || expected.length !== signature.length) return false;
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature),
);
}package webhook
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
)
func Verify(body []byte, signature, secret string) bool {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(body)
expected := hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(expected), []byte(signature))
}require "openssl"
def verify(body, signature, secret)
expected = OpenSSL::HMAC.hexdigest("SHA256", secret, body)
Rack::Utils.secure_compare(expected, signature.to_s)
endகட்டமைப்புக்கேற்ப இணைப்பு
from fastapi import FastAPI, HTTPException, Request
app = FastAPI()
@app.post("/thunderphone-webhook")
async def hook(request: Request):
body = await request.body() # raw bytes, NOT request.json()
sig = request.headers.get("X-ThunderPhone-Signature", "")
if not verify(body, sig, SECRET):
raise HTTPException(status_code=401)
import json
event = json.loads(body)
# … dispatch on event["type"] …
return {"ok": True}import express from "express";
const app = express();
app.post(
"/thunderphone-webhook",
// IMPORTANT: parse as raw; do NOT use express.json() here.
express.raw({ type: "application/json" }),
(req, res) => {
const sig = req.header("X-ThunderPhone-Signature") || "";
if (!verify(req.body, sig, process.env.WEBHOOK_SECRET)) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body.toString("utf8"));
// … dispatch on event.type …
res.sendStatus(204);
},
);import json
from django.http import JsonResponse, HttpResponseForbidden
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
@csrf_exempt
@require_POST
def hook(request):
body = request.body # raw bytes
sig = request.headers.get("X-ThunderPhone-Signature", "")
if not verify(body, sig, SECRET):
return HttpResponseForbidden("invalid signature")
event = json.loads(body)
# … dispatch on event["type"] …
return JsonResponse({"ok": True})டூல் அழைப்புகளைச் சரிபார்த்தல்
ஏஜென்ட் உங்கள் செயல்பாட்டு டூல்களில் ஒன்றை நேரடியாக
அழைக்கும்போது (அந்த டூலுக்கு ஒரு endpoint இருக்கும்), கோரிக்கையில்
நீங்கள் கட்டமைத்துள்ள endpoint.headers உடன் இந்த இரண்டு ThunderPhone
தலைப்புகளும் இருக்கும்:
X-ThunderPhone-Call-ID— நடப்பிலுள்ள அழைப்பின் எண் அடையாளம்.X-ThunderPhone-Signature— துல்லியமான கோரிக்கை-உடல் பைட்டுகளின் மீது, உங்கள் நிறுவன-நிலை வெப்ஹூக் ரகசியத்தை விசையாகக் கொண்ட HMAC-SHA256.
அதே verify() உதவியாளர் மாற்றமின்றி செயல்படும்; ஆனால் இரண்டு கவனிக்க வேண்டியவை உள்ளன:
GET/DELETEடூல்களுக்கு உடல் இருக்காது. அளவுருக்கள் வினவல் அளவுருக்களாக அனுப்பப்படும்; கையொப்பம் வெற்று பைட் சரத்தின் மீது கணக்கிடப்படும் — அதாவதுverify(b"", sig, secret)(Python) அல்லதுverify(Buffer.alloc(0), sig, secret)(Node). வினவல் சரத்தை ஹாஷ் செய்யாதீர்கள்.- பழைய வெப்ஹூக் கட்டமைக்கப்படாத நிறுவனங்களுக்கு நிறுவன ரகசியம் இருக்காது.
அந்த நிலையில் டூல் அழைப்புகள்
X-ThunderPhone-Call-IDமட்டுமே கொண்டிருக்கும்; கையொப்பத் தலைப்பு இருக்காது. கையொப்ப ரகசியத்தைப் பெற பழைய வெப்ஹூக்கை (PUT /v1/webhook) கட்டமைக்கவும் அல்லதுendpoint.headersமூலம் உங்கள் சொந்தத் தலைப்பைப் பயன்படுத்தி டூல் அழைப்புகளை அங்கீகரிக்கவும்.
@app.post("/tools/search-appointments")
async def tool(request: Request):
body = await request.body() # b"" for GET/DELETE tools
sig = request.headers.get("X-ThunderPhone-Signature", "")
call_id = request.headers.get("X-ThunderPhone-Call-ID", "")
if not verify(body, sig, ORG_WEBHOOK_SECRET):
raise HTTPException(status_code=401)
args = json.loads(body)
...வெப்ஹூக்-பயன்முறை டூல் அனுப்புதல் (endpoint இல்லாத டூல்கள்,
உங்கள் நிறுவன வெப்ஹூக்கிற்கு telephony.tool / web.tool ஆக
அனுப்பப்படுபவை) ஒரு சாதாரண கையொப்பமிடப்பட்ட வெப்ஹூக் ஆகும் — மேலே உள்ள
நிலையான முறையே பொருந்தும். இரண்டு கோரிக்கை வடிவங்களுக்கும்
செயல்பாட்டு டூல்களை பார்க்கவும்.
பொதுவான சிக்கல்கள்
இயல்புநிலை வடிவமைப்புடன் மீண்டும் வரிசைப்படுத்துதல்
body-ஐப் பாகுபடுத்தி, உங்கள் JSON நூலகத்தின் இயல்புநிலை அமைப்புகளுடன்
(, / :-க்குப் பின் இடைவெளிகள், சேர்க்கை வரிசையிலான key-கள்) மீண்டும் வெளியிடுவது
வேறுபட்ட byte-களை உருவாக்கி HMAC-ஐ செயலிழக்கச் செய்கிறது. மூல body-ஐச் சரிபார்க்கவும் — அல்லது
நீங்கள் மீண்டும் வரிசைப்படுத்த வேண்டியிருந்தால், எங்கள் நியம வடிவத்துடன் துல்லியமாகப் பொருத்தவும்:
வரிசைப்படுத்தப்பட்ட key-கள், சுருக்கமான பிரிப்பான்கள், UTF-8.
Framework தானாக JSON-ஐப் பாகுபடுத்துகிறது
Express-இன் express.json() middleware body stream-ஐப் பயன்படுத்திவிடும்;
இதனால் மூல byte-களை இழப்பீர்கள். webhook route-க்கு மட்டும் express.raw()-ஐப் பயன்படுத்தவும்,
அல்லது pre-middleware-இல் மூல body-ஐ buffer செய்யவும்.
NestJS / Koa-விற்கும் இதுவே பொருந்தும் — அவற்றின் "raw body" ஆவணங்களைப் பார்க்கவும்.
நேர-பாதுகாப்பற்ற ஒப்பீடு
JS-இல் expected === signature அல்லது Python-இல் expected == signature
நேரத்தைப் பொறுத்து மாறும் ஒப்பீடுகள். முறையே crypto.timingSafeEqual
அல்லது hmac.compare_digest-ஐப் பயன்படுத்தவும். செயல்திறன் வேறுபாடு
இல்லை.
Tool endpoint-களுக்கான தவறான ரகசியம்
நேரடி tool-endpoint அழைப்புகள் org-நிலை webhook
ரகசியம் (GET /v1/webhook) மூலம் கையொப்பமிடப்படுகின்றன —
/v1/developer/webhook-endpoints-இலுள்ள endpoint-தனிப்பட்ட ரகசியம் மூலம் அல்ல. அதே verify()
செயல்பாட்டை மீண்டும் பயன்படுத்தவும்; ஆனால் tool route-களில் அதற்கு org ரகசியத்தையே வழங்குவதை உறுதிசெய்யவும்.
GET/DELETE tool-களில் query string-ஐ hash செய்தல்
body இல்லாத tool முறைகளில், கையொப்பம் வெற்று byte string-ஐ உள்ளடக்கும்; இதனால் ஒரே பொதுவான நடைமுறை கிடைக்கிறது: மூல கோரிக்கை body எதுவாக இருந்தாலும், அதையே HMAC செய்யவும். URL அல்லது query string-ஐ hash செய்தால் ஒருபோதும் பொருந்தாது.
பொருந்தாதபோது 401-ஐ வழங்காமை
சரிபார்ப்பு தோல்வியடைந்தபோது 200-ஐ வழங்குவது handler-ஐ replay இலக்காக மாற்றுகிறது. சரிபார்ப்பு தோல்வியடைந்தால் எப்போதும் 2xx அல்லாத பதிலை வழங்கவும்.
அடுத்த படிகள்
விநியோக அர்த்தவியல், மீண்டும் முயற்சிகள், மூல IP-கள்.
பல URL-களை நிர்வகிக்கவும், ரகசியங்களை மாற்றவும்.
இரண்டு tool-invocation பாதைகள் மற்றும் அவற்றின் கோரிக்கை வடிவங்கள்.
தொடக்கம் முதல் முடிவு வரை முழுமையான tool-ஆதரவு ஒருங்கிணைப்பை உருவாக்கவும்.