Panduan11 menit baca
Verifikasi tanda tangan webhook formulir
Pastikan webhook formulir benar-benar berasal dari Ikiform: skema HMAC-SHA256 Standard Webhooks, test vector, body mentah, timestamp, dan rotasi secret.
Hitung ulang tanda tangan sendiri dan bandingkan dengan yang ada di request. Ikiform mengikuti Standard Webhooks: tanda tangannya adalah HMAC-SHA256 base64 dari webhook-id, webhook-timestamp, dan body mentah yang digabung dengan titik, dengan key berupa bagian hasil decode base64 dari secret whsec_ Anda, dan dikirim sebagai v1,<signature>. Terima request hanya jika satu tanda tangan v1 cocok dalam perbandingan constant-time dan timestamp berada dalam 5 menit.
Endpoint webhook adalah URL publik yang menerima request POST dari siapa pun. Tanpa pemeriksaan tanda tangan, siapa pun yang tahu URL-nya bisa mengirim kiriman palsu ke CRM, database, atau chat tim Anda. Pemeriksaannya hanya beberapa baris kode, dan menulis baris-baris itu dengan tepat adalah inti panduan ini.
Cara kerja penandatanganan
Ikiform dan server Anda berbagi satu secret, yang ditampilkan sekali saat Anda menambahkan endpoint. Sebelum setiap percobaan pengiriman, Ikiform meng-hash request dengan secret itu dan menaruh hasilnya di header. Server Anda mengulang perhitungan itu pada apa yang diterimanya. Hanya pihak yang memegang secret yang bisa menghasilkan nilai yang cocok, dan perubahan apa pun pada body, id, atau timestamp akan merusaknya.
- Ikiform menserialisasi event sebagai JSON.
- Ikiform menggabungkan id pengiriman, Unix timestamp percobaan, dan body dengan titik.
- Ikiform menghitung HMAC-SHA256 dari string itu dengan setiap secret aktif milik endpoint.
- Ikiform mengirim setiap hasil, di-encode base64 dan diberi awalan v1, di header webhook-signature.
- Handler Anda membaca body mentah dan ketiga header sebelum mem-parsing apa pun.
- Handler menghitung HMAC yang sama dengan salinan secret-nya.
- Handler membandingkan secara constant-time dengan setiap tanda tangan v1 dan memeriksa timestamp berada dalam 5 menit.
- Jika cocok, handler menjawab 2xx dan menangani event. Jika tidak, handler menjawab 400 dan tidak melakukan apa pun.
Skemanya, secara persis
Ikiform memakai Standard Webhooks, spesifikasi terbuka yang dipakai bersama oleh beberapa penyedia webhook. Setiap pengiriman membawa tiga header:
| Header | Nilai | Catatan |
|---|---|---|
webhook-id | dlv_... | Id pengiriman. Sama di setiap percobaan ulang, jadi sekaligus berfungsi sebagai idempotency key |
webhook-timestamp | Detik Unix, seperti 1792300000 | Kapan percobaan ini ditandatangani. Baru di setiap percobaan ulang |
webhook-signature | v1, ditambah base64 | Satu atau lebih nilai yang dipisahkan spasi. Dua saat secret sedang dirotasi |
webhook-id: dlv_01k7v2d4n8r2p6s0w3y5b7c9e1
webhook-timestamp: 1792300000
raw body: {"id":"dlv_01k7...","type":"endpoint.test",...}
signed content = webhook-id + "." + webhook-timestamp + "." + raw body
key = base64-decode(secret without "whsec_")
signature = base64(HMAC-SHA256(key, signed content))
header = "v1," + signatureUntuk memverifikasi pengiriman, dengan urutan ini:
- Baca body mentah sebagai byte atau string persis. Jangan di-parse dulu.
- Baca ketiga header. Jika ada yang hilang, tolak.
- Pastikan timestamp berupa bilangan bulat dalam 5 menit dari jam Anda, ke arah mana pun. Jika tidak, tolak.
- Hapus
whsec_dari secret Anda dan decode base64 sisanya. 32 byte itulah key HMAC-nya, bukan string itu sendiri. - Hitung HMAC-SHA256 dari
{webhook-id}.{webhook-timestamp}.{raw body}dan encode base64 dengan alfabet standar dan padding. - Pisahkan
webhook-signatureberdasarkan spasi. Untuk setiap entri, pisahkan di koma pertama; lewati apa pun yang versinya bukanv1. - Bandingkan setiap nilai
v1dengan milik Anda secara constant-time. Jika ada yang cocok, pengiriman itu asli. - Baru sekarang parse JSON dan tindak lanjuti.
Test vector
Sebelum men-deploy handler, buktikan bahwa handler menghitung nilai yang benar. Input ini adalah body pengiriman endpoint.test sungguhan yang ditandatangani dengan secret karangan. Kode Anda harus menghasilkan persis tanda tangan di baris terakhir. Setiap panduan bahasa menyertakan unit test yang memakainya.
| Input | Nilai |
|---|---|
| Secret | whsec_Fg8c6hm1Gt41v5RSPKm72LggDx8S1mlWkbBYpHPAnpw= |
webhook-id | dlv_01k7v2d4n8r2p6s0w3y5b7c9e1 |
webhook-timestamp | 1792300000 |
| Body mentah | Byte persis di script di bawah, tanpa spasi atau baris baru |
webhook-signature yang diharapkan | v1,Duq+Iuh0xbRZyS+C/TO5W1hcGLGwg+ifBiWiYkq15qA= |
Anda bisa memeriksanya tanpa menulis kode. Ini berjalan di terminal macOS atau Linux dan mencetak bagian base64 dari tanda tangan:
SECRET='whsec_Fg8c6hm1Gt41v5RSPKm72LggDx8S1mlWkbBYpHPAnpw='
ID='dlv_01k7v2d4n8r2p6s0w3y5b7c9e1'
TS='1792300000'
BODY='{"id":"dlv_01k7v2d4n8r2p6s0w3y5b7c9e1","type":"endpoint.test","timestamp":"2026-10-17T12:00:00.000Z","api_version":"2026-10-17","data":{"endpoint_id":"whk_01k7v2e1b3d5f7h9k1m3n5q7s9","message":"This is a test event from Ikiform."}}'
KEY=$(printf '%s' "${SECRET#whsec_}" | base64 -d | xxd -p -c 256)
printf '%s.%s.%s' "$ID" "$TS" "$BODY" \
| openssl dgst -sha256 -mac HMAC -macopt "hexkey:$KEY" -binary \
| base64Dua kasus lagi layak diuji masing-masing, karena keduanya adalah kegagalan nyata yang paling umum:
| Perubahan | Tanda tangan | Haruskah handler Anda menerimanya? |
|---|---|---|
| Body yang sama diformat rapi dengan indentasi dua spasi | v1,se0TDhknrG0hYMvCId83HnpZfJcELG3ozxFJktRUHqY= | Tidak. JSON sama, byte berbeda |
webhook-timestamp satu detik kemudian | v1,oBfWyLDPfrwVSo40e6b7B7+LmKkZX7OqT88SsrpY6ks= | Tidak. Timestamp ikut ditandatangani |
| Ditandatangani dengan secret kedua saat rotasi | v1,gfHP3s7ANdIpnM7gewtWtSvTrHgmsbEFgCaeRRR0Eak= | Ya, jika header juga punya nilai yang cocok dengan secret Anda |
Saat rotasi secret, header membawa kedua nilai. Handler Anda, yang memegang salah satu secret, harus menerima ini:
webhook-id: dlv_01k7v2d4n8r2p6s0w3y5b7c9e1
webhook-timestamp: 1792300000
webhook-signature: v1,Duq+Iuh0xbRZyS+C/TO5W1hcGLGwg+ifBiWiYkq15qA= v1,gfHP3s7ANdIpnM7gewtWtSvTrHgmsbEFgCaeRRR0Eak=Cara memverifikasi
| Pendekatan | Unggul dalam | Kekurangan |
|---|---|---|
verifyWebhook dari @ikiform/sdk/webhooks | Satu panggilan yang memeriksa semuanya dan mengembalikan event bertipe. Berjalan di Node, Workers, Deno, dan Bun | Hanya JavaScript dan TypeScript |
| Library Standard Webhooks | Kode terawat untuk Python, Go, PHP, Ruby, JavaScript, Rust, Java, C#, dan Elixir | Satu dependency lagi. Periksa cara masing-masing menerima header; sebagian case-sensitive |
| Kode HMAC Anda sendiri | Tanpa dependency, sekitar 20 baris, dan Anda bisa menguji setiap cabang | Mudah keliru secara halus: perbandingan string, byte key yang salah, atau body yang sudah di-parse |
| Path rahasia atau token query sebagai gantinya | Sederhana | Bocor lewat log, proxy, dan error tracker, tidak membuktikan apa pun tentang body, dan tidak bisa kedaluwarsa. Bukan pengganti |
Ikiform menandatangani setiap pengiriman, dan tanda tangan adalah cara yang didukung untuk mengautentikasinya. Dokumentasinya tidak memublikasikan daftar tetap alamat IP pengirim, jadi allowlist IP bukan pemeriksaan yang bisa Anda andalkan.
Verifikasi di framework Anda
Untuk stack JavaScript, SDK yang melakukan pekerjaannya. Yang berbeda antar framework adalah di mana route berada dan cara mendapatkan body sebelum ada yang mem-parsing-nya. Pilih milik Anda:
Route handler App Router. request.text() adalah body mentah; memanggil request.json() lebih dulu akan menghilangkannya. Panduan server sendiri menambahkan dedupe dan after().
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";
export async function POST(request: Request) {
const payload = await request.text();
try {
const event = await verifyWebhook({
payload,
headers: request.headers,
secret: process.env.IKIFORM_WEBHOOK_SECRET!,
});
console.info(event.type, request.headers.get("webhook-id"));
return new Response(null, { status: 204 });
} catch (error) {
if (error instanceof WebhookVerificationError) return new Response(error.reason, { status: 400 });
throw error;
}
}Endpoint dengan ekspor POST. Endpoint ini butuh rendering on demand, jadi pertahankan prerender = false dan sebuah adapter. getSecret dari astro:env/server membaca IKIFORM_WEBHOOK_SECRET saat runtime dan hanya di server; import.meta.env akan menanamnya ke dalam build.
import type { APIRoute } from "astro";
import { getSecret } from "astro:env/server";
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";
export const prerender = false;
export const POST: APIRoute = async ({ request }) => {
const payload = await request.text();
try {
const event = await verifyWebhook({
payload,
headers: request.headers,
secret: getSecret("IKIFORM_WEBHOOK_SECRET") ?? "",
});
console.info(event.type, event.id);
return new Response(null, { status: 204 });
} catch (error) {
if (error instanceof WebhookVerificationError) return new Response(error.reason, { status: 400 });
throw error;
}
};Server route: route berbasis file yang sama, dengan function server.handlers.POST yang menerima Request standar.
import { createFileRoute } from "@tanstack/react-router";
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";
export const Route = createFileRoute("/api/webhooks/ikiform")({
server: {
handlers: {
POST: async ({ request }) => {
const payload = await request.text();
try {
const event = await verifyWebhook({
payload,
headers: request.headers,
secret: process.env.IKIFORM_WEBHOOK_SECRET!,
});
console.info(event.type, event.id);
return new Response(null, { status: 204 });
} catch (error) {
if (error instanceof WebhookVerificationError) return new Response(error.reason, { status: 400 });
throw error;
}
},
},
},
});Resource route: modul dengan action dan tanpa default export, didaftarkan di routes.ts. Route ini menjawab Ikiform langsung alih-alih merender halaman.
import { type RouteConfig, index, route } from "@react-router/dev/routes";
export default [
index("routes/home.tsx"),
route("webhooks/ikiform", "routes/webhooks.ikiform.ts"),
] satisfies RouteConfig;import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";
import type { Route } from "./+types/webhooks.ikiform";
export async function action({ request }: Route.ActionArgs) {
if (request.method !== "POST") return new Response(null, { status: 405 });
const payload = await request.text();
try {
const event = await verifyWebhook({
payload,
headers: request.headers,
secret: process.env.IKIFORM_WEBHOOK_SECRET!,
});
console.info(event.type, event.id);
return new Response(null, { status: 204 });
} catch (error) {
if (error instanceof WebhookVerificationError) return new Response(error.reason, { status: 400 });
throw error;
}
}Endpoint +server.ts. Pemeriksaan CSRF bawaan SvelteKit hanya memblokir content type formulir lintas situs, dan Ikiform mengirim application/json, jadi tidak perlu mengubah config. Deklarasikan IKIFORM_WEBHOOK_SECRET di src/env.ts dengan defineEnvVars agar $app/env/private bisa membacanya.
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";
import { IKIFORM_WEBHOOK_SECRET } from "$app/env/private";
import type { RequestHandler } from "./$types";
export const POST: RequestHandler = async ({ request }) => {
const payload = await request.text();
try {
const event = await verifyWebhook({ payload, headers: request.headers, secret: IKIFORM_WEBHOOK_SECRET });
console.info(event.type, event.id);
return new Response(null, { status: 204 });
} catch (error) {
if (error instanceof WebhookVerificationError) return new Response(error.reason, { status: 400 });
throw error;
}
};Server route Nitro. readRawBody mengembalikan body sebagai string sebelum ada yang mem-parsing-nya. Atur NUXT_IKIFORM_WEBHOOK_SECRET dan deklarasikan ikiformWebhookSecret di bawah runtimeConfig di nuxt.config.ts.
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";
export default defineEventHandler(async (event) => {
const payload = (await readRawBody(event, "utf8")) ?? "";
const { ikiformWebhookSecret } = useRuntimeConfig(event);
try {
const delivery = await verifyWebhook({
payload,
headers: getRequestHeaders(event),
secret: ikiformWebhookSecret,
});
console.info(delivery.type, delivery.id);
setResponseStatus(event, 204);
return null;
} catch (error) {
if (error instanceof WebhookVerificationError) {
throw createError({ status: 400, message: error.reason });
}
throw error;
}
});Setiap handler menjawab 204 saat sukses dan 400 beserta alasan kegagalan jika tidak. Lakukan pekerjaan lambat setelah menjawab; Ikiform menunggu 15 detik sebelum menganggap percobaan gagal.
Mengapa body mentah penting
Tanda tangan mencakup byte, bukan makna. {"a":1} dan { "a": 1 } adalah JSON yang sama dengan byte berbeda, jadi body yang sudah di-parse lalu diserialisasi ulang hampir tidak pernah cocok. Hal yang sama berlaku untuk apa pun yang menyentuh body saat masuk: middleware yang mem-parsing JSON, proxy yang meng-encode ulang, atau framework yang memberi Anda objek alih-alih string.
Baca body sekali, sebagai byte atau string, verifikasi, lalu parse string yang sama itu. Setiap panduan bahasa menunjukkan di mana body mentah berada di framework-nya, dan panduan server sendiri punya tabel untuk framework Node dan Python yang umum.
Bandingkan secara constant-time
Perbandingan string biasa berhenti di karakter pertama yang berbeda. Secara teori, penyerang yang bisa mengukur waktu ribuan request akan tahu berapa banyak karakter awal tebakannya yang benar dan menyusun tanda tangan valid satu karakter demi satu karakter. Perbandingan constant-time memakan waktu yang sama berapa pun bagian yang cocok. Setiap bahasa punya:
| Bahasa | Perbandingan constant-time |
|---|---|
| Node.js | crypto.timingSafeEqual(a, b), yang melempar error jika panjangnya berbeda, jadi periksa panjang lebih dulu |
| Python | hmac.compare_digest(a, b) |
| Go | hmac.Equal(a, b) |
| PHP | hash_equals($known, $user) |
| Ruby | OpenSSL.secure_compare(a, b), atau ActiveSupport::SecurityUtils.secure_compare di Rails |
Timestamp dan replay
Request valid yang tertangkap sekali akan tetap valid selamanya kecuali ada yang membuatnya kedaluwarsa. Timestamp yang ditandatangani itulah yang melakukannya: tolak pengiriman apa pun yang selisihnya lebih dari 5 menit dari jam Anda, ke arah mana pun. Karena Ikiform menandatangani ulang setiap percobaan dengan timestamp baru, percobaan ulang tiga hari kemudian tetap lolos; hanya request lama yang disalin yang gagal.
Dalam 5 menit itu, replay masih mungkin, begitu pula duplikat yang asli: Ikiform mencoba ulang saat tidak mendapat 2xx tepat waktu, meski handler Anda sudah selesai. Simpan webhook-id dengan unique constraint dan lewati id yang sudah Anda tangani. Itu menutup keduanya.
timestamp_too_old atau timestamp_too_new. Platform terkelola biasanya menjaga jam tetap sinkron; di VM Anda sendiri, jalankan NTP.Merotasi secret
Rotasi secret saat orang yang mengetahuinya keluar, saat secret mungkin tercatat di log atau ter-commit, atau secara terjadwal. Roll signing secret di halaman endpoint membuat secret baru, dan selama 24 jam setiap pengiriman ditandatangani dengan keduanya:
- Sebelum rotasi, setiap pengiriman membawa satu tanda tangan, dibuat dengan secret lama.
- Anda memilih Roll signing secret dan menyalin secret baru.
- Selama 24 jam berikutnya, setiap pengiriman membawa dua tanda tangan, jadi server yang memegang salah satu secret akan menerimanya. Deploy secret baru dalam jendela waktu ini.
- Setelah 24 jam, pengiriman hanya membawa tanda tangan baru, dan server yang masih memegang secret lama menolaknya.
Jika secret lama masih ter-deploy setelah 24 jam, setiap pengiriman gagal. Ikiform mencoba ulang masing-masing 8 kali selama sekitar tiga hari, jadi setelah Anda men-deploy secret yang benar, gunakan Retry di log pengiriman untuk yang sudah menyerah.
Setelah pemeriksaan lolos
Tanda tangan yang valid membuktikan request berasal dari Ikiform dan tidak diubah. Itu tidak membuktikan kontennya aman atau baru. Tiga kebiasaan menyelesaikan pekerjaan ini:
- Lewati pengulangan. Simpan
webhook-id, atauiddi payload, yang nilainya sama, dengan unique constraint. Percobaan ulang dari pengiriman yang sudah Anda tangani menjadi no-op. - Jawab dulu, kerjakan belakangan. Kembalikan
2xxbegitu event disimpan atau dimasukkan ke antrean. Ikiform menganggap apa pun yang lebih lambat dari 15 detik sebagai kegagalan dan mencoba ulang, yang memunculkan kembali masalah duplikat. - Perlakukan field sebagai tidak tepercaya.
data.fieldsberisi apa yang diketik pengunjung di formulir publik. Escape sebelum merendernya di HTML, pesan chat, atau email, dan jangan pernah meneruskannya ke shell atau query tanpa parameter.
Menguji sebelum live
Ikiform hanya mengirim ke URL https: publik di port 443, jadi localhost tidak bisa menerima webhook. Jalankan tunnel seperti cloudflared tunnel --url http://localhost:3000 dan tambahkan URL yang dicetaknya sebagai endpoint kedua selama Anda bekerja. Send test di halaman endpoint mengirim event endpoint.test sekali, tanpa percobaan ulang, ditandatangani persis seperti pengiriman sungguhan. Hapus endpoint uji setelah selesai; endpoint itu punya secret sendiri, jadi tidak ada yang lain berubah.
Jika pengiriman gagal dan Anda tidak tahu sebabnya, salin header dan body-nya dari log Anda ke signature verifier. Alat itu menjalankan pemeriksaan yang sama di browser dan memberi tahu langkah mana yang gagal.
Lima cara verifikasi bisa salah
| Kesalahan | Gejala | Solusi |
|---|---|---|
Memakai seluruh string whsec_... sebagai key | no_matching_signature di setiap pengiriman | Hapus whsec_, lalu decode base64. Key-nya 32 byte |
| Memverifikasi body yang sudah di-parse | no_matching_signature, terkadang hanya untuk sebagian payload | Verifikasi body mentah; parse sesudahnya |
| Hanya memeriksa tanda tangan pertama | Kegagalan yang dimulai tepat setelah rotasi | Loop setiap entri v1 yang dipisahkan spasi |
| Heksadesimal alih-alih base64 | no_matching_signature | Standard Webhooks memakai base64 standar dengan padding, bukan hex atau base64url |
| Mencari header dengan huruf besar-kecil yang persis | missing_headers di balik beberapa proxy | Nama header tidak peka huruf besar-kecil. Ikiform mengirimnya dalam huruf kecil; cari tanpa memedulikan huruf besar-kecil |
Tidak ada integrasi sekali klik. Setiap alat dijangkau lewat webhook bertanda tangan, langsung atau melalui alat otomasi seperti Zapier atau n8n. Satu workspace bisa punya 3 endpoint, masing-masing dengan secret sendiri. Payload lengkap, jadwal percobaan ulang, dan log pengiriman ada di Webhooks.
Pilih situasi Anda
Setiap halaman bahasa berisi handler yang idiomatis, opsi library, dan unit test yang menjalankan test vector dari halaman ini.
- Node.jsVerifikasi tanda tangan webhook Ikiform di Node.js: body mentah di Express dan Fastify, SDK, paket standardwebhooks, dan versi node:crypto yang sudah diuji.
- PythonVerifikasi tanda tangan webhook Ikiform di Flask, FastAPI, dan Django, dengan paket standardwebhooks atau standard library, ditambah test pytest.
- Go net/httpVerifikasi tanda tangan webhook Ikiform di Go dengan net/http: baca body sekali, periksa dengan crypto/hmac, uji, atau gunakan library Standard Webhooks.
- PHPVerifikasi tanda tangan webhook Ikiform di PHP biasa dengan hash_hmac dan hash_equals, dan di Laravel dengan library Standard Webhooks dan pengecualian CSRF.
- RubyVerifikasi tanda tangan webhook Ikiform di Sinatra dengan OpenSSL dan test Minitest, dan di Rails dengan gem standardwebhooks dan request.raw_post.
Pastikan berfungsi
Lakukan ini di endpoint staging dulu, lalu sekali lagi di produksi. Ikiform tidak punya paket gratis. Pengujian gratis: workspace tanpa paket menerima 50 kiriman uji per bulan dari localhost. Untuk live, pilih Pro mulai $6/bln untuk 500 kiriman, atau bayar sekali: 10.000 kiriman seharga $49 atau 50.000 kiriman seharga $149, dengan kredit yang tidak pernah kedaluwarsa. Lihat harga.
- Jalankan test vector lewat kode Anda: kode harus menghasilkan tanda tangan yang diharapkan, menerima header dengan dua tanda tangan, dan menolak body yang diformat rapi.
- Di dashboard, buka Webhooks, tambahkan URL
https:publik endpoint Anda, dan salin secretwhsec_ke environment server Anda. - Pilih Send test di halaman endpoint. Log pengiriman menampilkan
204Anda dan event sampai ke log Anda. - Ubah satu karakter secret di server Anda dan kirim uji lagi. Log menampilkan
400denganno_matching_signature. - Kirim formulir sungguhan dan pastikan pengiriman
submission.createdberhasil.
Pemecahan masalah
| Masalah | Yang harus dilakukan |
|---|---|
400 no_matching_signature | Secret salah, body sudah di-parse, atau key yang tidak di-decode base64. Jalankan test vector lewat jalur kode yang sama untuk melihat yang mana. |
400 timestamp_too_old atau timestamp_too_new | Jam server meleset, atau Anda memutar ulang request tersimpan secara manual. Sinkronkan jam, dan gunakan Retry di log pengiriman, yang menandatangani ulang. |
400 missing_headers | Proxy atau framework membuang header webhook-*, atau request tidak berasal dari Ikiform. Catat setiap nama header yang dilihat handler Anda. |
| Berhasil untuk event uji, gagal untuk kiriman sungguhan | Payload sungguhan berisi karakter non-ASCII dan teks yang lebih panjang. Kode Anda men-decode atau meng-encode ulang body sebelum verifikasi. Verifikasi byte yang persis. |
| Setiap pengiriman gagal tepat setelah merotasi secret | Handler hanya memeriksa tanda tangan pertama, atau 24 jam sudah lewat dengan secret lama masih ter-deploy. Periksa setiap entri v1 dan deploy secret baru. |
| Log pengiriman menampilkan timeout, padahal handler Anda berjalan | Ikiform menunggu 15 detik. Jawab dulu dan lakukan pekerjaan lambat sesudahnya, dan lewati nilai webhook-id yang berulang. |
Pertanyaan
Hitung ulang HMAC-SHA256 dari id webhook, timestamp, dan body mentah yang digabung dengan titik, memakai bagian hasil decode base64 dari secret whsec_ Anda sebagai key. Encode hasilnya dengan base64 dan bandingkan secara constant-time dengan setiap nilai v1 di header webhook-signature.
Hampir selalu salah satu dari tiga hal: body di-parse dan diserialisasi ulang sebelum verifikasi, seluruh string whsec_ dipakai sebagai key alih-alih byte hasil decode base64-nya, atau secret-nya milik endpoint lain.
Spesifikasi terbuka untuk menandatangani webhook dengan HMAC-SHA256 dan header webhook-id, webhook-timestamp, dan webhook-signature. Ikiform mengikutinya, jadi library Standard Webhooks apa pun bisa memverifikasi pengiriman Ikiform.
Jika tidak, request yang tertangkap akan tetap valid selamanya. Menolak apa pun yang selisihnya lebih dari 5 menit dari jam Anda menghentikan replay request lama, dan Ikiform menandatangani setiap percobaan ulang dengan timestamp baru, jadi percobaan ulang yang asli tetap lolos.
Selama 24 jam setiap pengiriman ditandatangani dengan secret lama maupun baru, jadi Anda bisa men-deploy yang baru tanpa kehilangan event. Setelah itu hanya secret baru yang berfungsi.
Keduanya boleh bagi Ikiform; status apa pun selain 2xx dianggap kegagalan dan dicoba ulang. Jangan kembalikan 410, yang langsung menonaktifkan endpoint.
Mentok di salah satu langkah, atau ingin panduan untuk situasi Anda? Email hello@ikiform.com.