Open in
ವೆಬ್ಹುಕ್ ಸಹಿಗಳನ್ನು ಪರಿಶೀಲಿಸಿ
ThunderPhone ಕಳುಹಿಸುವ ಪ್ರತಿಯೊಂದು ವೆಬ್ಹುಕ್ ಮತ್ತು ಉಪಕರಣ ವಿನಂತಿಗೆ ಸಹಿ ಮಾಡಲಾಗಿರುತ್ತದೆ. ಇಲ್ಲಿನ ಕ್ರಮವನ್ನು ಬಳಸಿ ಸಹಿಯನ್ನು ಒಮ್ಮೆ ಪರಿಶೀಲಿಸಿ, ನಂತರ ನೀವು ನಿರ್ವಹಿಸುವ ಪ್ರತಿಯೊಂದು ಎಂಡ್ಪಾಯಿಂಟ್ನಲ್ಲಿ ಅದೇ ಪರಿಶೀಲನೆಯನ್ನು ಮರುಬಳಸಿ.
ನಾವು ನಿಮ್ಮ ಸರ್ವರ್ಗೆ ಕಳುಹಿಸುವ ಪ್ರತಿಯೊಂದು ವಿನಂತಿಯು — ವೆಬಹುಕ್ ವಿತರಣೆಗಳು ಮತ್ತು ಟೂಲ್-ಎಂಡ್ಪಾಯಿಂಟ್ ಆಹ್ವಾನಗಳು — X-ThunderPhone-Signature ಹೆಡರ್ನಲ್ಲಿ HMAC-SHA256 ಸಹಿಯನ್ನು ಹೊಂದಿರುತ್ತದೆ. ಪರಿಶೀಲನೆಯನ್ನು ಒಮ್ಮೆ ಸರಿಯಾಗಿ ಅಳವಡಿಸಿಕೊಳ್ಳಿ ಮತ್ತು ಅದೇ ಸಹಾಯಕವನ್ನು ಪ್ರತಿಯೊಂದು ಹ್ಯಾಂಡ್ಲರ್ಗೆ ಸೇರಿಸಿ.
ಅಲ್ಗಾರಿದಮ್
- ಮೂಲ ವಿನಂತಿ ಬಾಡಿಯನ್ನು ಓದಿ — ನಾವು ನಿಮಗೆ ಕಳುಹಿಸಿದ ನಿಖರ ಬೈಟ್ಗಳು.
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 ವೆಬಹುಕ್ನದ್ದೇ) — ಎಂಡ್ಪಾಯಿಂಟ್-ಪ್ರತ್ಯೇಕ ರಹಸ್ಯವಲ್ಲ |
ರಹಸ್ಯವನ್ನು ನಿಮ್ಮ ರಹಸ್ಯ ನಿರ್ವಾಹಕ ಅಥವಾ ಪರಿಸರ ಚರದಲ್ಲಿ ಸಂಗ್ರಹಿಸಿ — ಅದನ್ನು ಎಂದಿಗೂ ಕಮಿಟ್ ಮಾಡಬೇಡಿ.
ಉಲ್ಲೇಖ ಅನುಷ್ಠಾನಗಳು
ಎಲ್ಲ ನಾಲ್ಕೂ ಮೂಲ ವಿನಂತಿ ಬಾಡಿಯನ್ನು ಪರಿಶೀಲಿಸುತ್ತವೆ:
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 ಆಗಿ ತಲುಪಿಸುವ ಟೂಲ್ಗಳು) ಸಾಮಾನ್ಯ
ಸಹಿ ಮಾಡಿದ ವೆಬ್ಹುಕ್ ಅನ್ವಯಿಸುತ್ತದೆ — ಮೇಲಿನ ಪ್ರಮಾಣಿತ ವಿಧಾನವನ್ನು ಬಳಸಿ.
ಎರಡೂ ವಿನಂತಿ ಸ್ವರೂಪಗಳಿಗಾಗಿ ಫಂಕ್ಷನ್ ಟೂಲ್ಗಳನ್ನು ನೋಡಿ.
ಸಾಮಾನ್ಯ ತಪ್ಪುಗಳು
ಡೀಫಾಲ್ಟ್ ಫಾರ್ಮ್ಯಾಟಿಂಗ್ನೊಂದಿಗೆ ಮರು-ಸೀರಿಯಲೈಸ್ ಮಾಡುವುದು
ಬಾಡಿಯನ್ನು ಪಾರ್ಸ್ ಮಾಡಿ ನಿಮ್ಮ JSON ಲೈಬ್ರರಿಯ ಡೀಫಾಲ್ಟ್ಗಳೊಂದಿಗೆ
ಮರು-ಡಂಪ್ ಮಾಡುವುದರಿಂದ (, / : ನಂತರದ ಖಾಲಿ ಜಾಗಗಳು, ಸೇರಿಸಿದ ಕ್ರಮದ ಕೀಲಿಗಳು)
ವಿಭಿನ್ನ ಬೈಟ್ಗಳು ಉತ್ಪತ್ತಿಯಾಗುತ್ತವೆ ಮತ್ತು HMAC ವಿಫಲಗೊಳ್ಳುತ್ತದೆ. ಮೂಲ ಬಾಡಿಯನ್ನು ಪರಿಶೀಲಿಸಿ — ಅಥವಾ ನೀವು
ಮರು-ಸೀರಿಯಲೈಸ್ ಮಾಡಲೇಬೇಕಾದರೆ, ನಮ್ಮ ಪ್ರಮಾಣಿತ ರೂಪಕ್ಕೆ ನಿಖರವಾಗಿ ಹೊಂದಿಸಿ: ವಿಂಗಡಿಸಿದ
ಕೀಲಿಗಳು, ಸಂಕ್ಷಿಪ್ತ ವಿಭಜಕಗಳು, UTF-8.
ಫ್ರೇಮ್ವರ್ಕ್ JSON ಅನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಪಾರ್ಸ್ ಮಾಡುತ್ತದೆ
Express ನ express.json() ಮಿಡಲ್ವೇರ್ ಬಾಡಿ ಸ್ಟ್ರೀಮ್ ಅನ್ನು
ಬಳಸಿಕೊಳ್ಳುತ್ತದೆ ಮತ್ತು ನೀವು ಮೂಲ ಬೈಟ್ಗಳನ್ನು ಕಳೆದುಕೊಳ್ಳುತ್ತೀರಿ. ವೆಬ್ಹುಕ್
ರೂಟ್ನಲ್ಲಿ ನಿರ್ದಿಷ್ಟವಾಗಿ express.raw() ಬಳಸಿ, ಅಥವಾ ಪೂರ್ವ-ಮಿಡಲ್ವೇರ್ನಲ್ಲಿ ಮೂಲ ಬಾಡಿಯನ್ನು ಬಫರ್ ಮಾಡಿ.
NestJS / Koaಗೂ ಇದೇ ಅನ್ವಯಿಸುತ್ತದೆ — ಅವುಗಳ "ಮೂಲ ಬಾಡಿ" ದಾಖಲೆಗಳನ್ನು ಪರಿಶೀಲಿಸಿ.
ಸಮಯ-ಸುರಕ್ಷಿತವಲ್ಲದ ಹೋಲಿಕೆ
JS ನಲ್ಲಿ expected === signature ಅಥವಾ Python ನಲ್ಲಿ expected == signature
ಸಮಯಕ್ಕೆ ಅನುಗುಣವಾಗಿ ಬದಲಾಗುವ ಹೋಲಿಕೆಗಳಾಗಿವೆ. ಕ್ರಮವಾಗಿ crypto.timingSafeEqual
ಅಥವಾ hmac.compare_digest ಬಳಸಿ. ಕಾರ್ಯಕ್ಷಮತೆಯ ವ್ಯತ್ಯಾಸ
ಶೂನ್ಯವಾಗಿದೆ.
ಟೂಲ್ ಎಂಡ್ಪಾಯಿಂಟ್ಗಳಿಗೆ ತಪ್ಪು ರಹಸ್ಯ
ನೇರ ಟೂಲ್-ಎಂಡ್ಪಾಯಿಂಟ್ ಕರೆಗಳಿಗೆ ಸಂಸ್ಥೆ-ಮಟ್ಟದ ವೆಬ್ಹುಕ್
ರಹಸ್ಯ (GET /v1/webhook) ಬಳಸಿ ಸಹಿ ಮಾಡಲಾಗುತ್ತದೆ —
/v1/developer/webhook-endpoints ನಲ್ಲಿನ ಯಾವುದೇ ಪ್ರತಿ-ಎಂಡ್ಪಾಯಿಂಟ್ ರಹಸ್ಯವನ್ನು ಬಳಸಲಾಗುವುದಿಲ್ಲ. ಅದೇ verify()
ಫಂಕ್ಷನ್ ಅನ್ನು ಮರುಬಳಸಿ, ಆದರೆ ಟೂಲ್ ರೂಟ್ಗಳಲ್ಲಿ ಅದಕ್ಕೆ ಸಂಸ್ಥೆಯ ರಹಸ್ಯವನ್ನೇ ನೀಡುತ್ತಿರುವುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ.
GET/DELETE ಟೂಲ್ಗಳಲ್ಲಿ ಕ್ವೆರಿ ಸ್ಟ್ರಿಂಗ್ ಅನ್ನು ಹ್ಯಾಶ್ ಮಾಡುವುದು
ಬಾಡಿಯಿಲ್ಲದ ಟೂಲ್ ವಿಧಾನಗಳಿಗೆ ಸಹಿಯು ಖಾಲಿ ಬೈಟ್ ಸ್ಟ್ರಿಂಗ್ ಅನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ, ಇದರಿಂದ ಒಂದೇ ಸಾರ್ವತ್ರಿಕ ವಿಧಾನ ಉಳಿಯುತ್ತದೆ: ಮೂಲ ವಿನಂತಿ ಬಾಡಿ ಏನೇ ಇದ್ದರೂ ಅದಕ್ಕೆ HMAC ಮಾಡಿ. URL ಅಥವಾ ಕ್ವೆರಿ ಸ್ಟ್ರಿಂಗ್ ಅನ್ನು ಹ್ಯಾಶ್ ಮಾಡಿದರೆ ಎಂದಿಗೂ ಹೊಂದಿಕೆಯಾಗುವುದಿಲ್ಲ.
ಹೊಂದಿಕೆಯಾಗದಾಗ 401 ಹಿಂತಿರುಗಿಸದಿರುವುದು
ಪರಿಶೀಲನೆ ವಿಫಲವಾದಾಗ 200 ಹಿಂತಿರುಗಿಸುವುದು ಹ್ಯಾಂಡ್ಲರ್ ಅನ್ನು ಮರುಕಳುಹಿಸುವ ದಾಳಿಯ ಗುರಿಯನ್ನಾಗಿಸುತ್ತದೆ. ಪರಿಶೀಲನೆ ವಿಫಲವಾದರೆ ಯಾವಾಗಲೂ 2xx ಅಲ್ಲದ ಪ್ರತಿಕ್ರಿಯೆ ನೀಡಿ.