HMAC — Bagaimana Webhook Tahu Anda Tidak Berbohong
Setiap server dapat mengirimkan permintaan POST ke endpoint webhook Anda. Tanda tangan HMAC adalah cara pengirim yang sah membuktikan mereka menulis payload — dan cara Anda memverifikasinya.
Setiap kali Stripe melakukan pembayaran dengan kartu, sistem mengirimkan notifikasi webhook. Setiap kali GitHub menggabungkan permintaan penggabungan, sistem mengirimkan notifikasi webhook. Platform-platform ini mengirimkan permintaan POST ke URL yang Anda berikan — namun ada kebenaran yang tidak nyaman: siapa pun dapat mengirimkan permintaan POST ke URL yang sama.
Maka bagaimana server Anda tahu bahwa permintaan tersebut benar-benar berasal dari Stripe dan bukan dari penyerang yang menebak URL endpoint Anda? Jawabannya adalah HMAC — dan setelah Anda memahaminya, Anda akan menyadari mengapa HMAC menjadi pendekatan standar di setiap platform API yang serius.
Masalah: Siapa Saja Bisa Mengirimkan POST ke Endpoint Anda
Endpoint webhook hanyalah URL. Mereka dapat diakses secara publik (karena harus, agar pengirim dapat mencapainya), dan mereka menerima permintaan POST. Tidak ada yang mencegah penyerang jahat membuat payload palsu dan mengirimkannya ke endpoint Anda.
Bayangkan handler webhook Anda melakukan hal ini saat menerima peristiwa:
if event["type"] == "payment.completed":
fulfill_order(event["data"]["order_id"])
Seorang penyerang yang tahu URL endpoint Anda dapat mengirimkan peristiwa palsu dengan ID pesanan apa saja yang mereka inginkan. Tanpa verifikasi, server Anda akan dengan senang hati memenuhi pesanan yang tidak pernah dibayar. payment.completed Anda membutuhkan cara untuk memverifikasi bahwa payload tersebut dibuat oleh seseorang yang memiliki rahasia yang Anda bagikan bersama — tanpa mengirimkan rahasia tersebut dalam permintaan.
Apa Itu HMAC?
. Ini adalah konstruksi yang menggabungkan fungsi hash kriptografi (biasanya SHA-256) dengan kunci rahasia untuk menghasilkan tanda tangan. Tanda tangan ini membuktikan dua hal:
HMAC berarti Kode Autentikasi Pesan Berbasis Hash— pesan dibuat oleh seseorang yang memiliki kunci rahasia
- Keaslian Integritas
- — pesan tidak diubah selama perjalanan Sifat kunci HMAC: Anda tidak dapat menghasilkan tanda tangan yang valid tanpa tahu rahasia. Dan Anda tidak dapat membalikkan tanda tangan untuk memulihkan rahasia. Ini adalah bukti satu arah.
HMAC dibandingkan dengan hash biasa
Hash biasa (seperti SHA-256) dari payload menyelesaikan masalah integritas tetapi tidak menyelesaikan masalah autentisitas. Seorang penyerang yang mengintersepsi payload yang valid dapat menghitung hash dari payload yang diubah. HMAC menggabungkan kunci rahasia Anda dalam setiap langkah proses hashing, sehingga tanpa kunci, Anda tidak dapat menghasilkan tanda tangan yang sesuai bahkan jika Anda tahu algoritma hash yang digunakan.
Cara HMAC Webhook Bekerja
Alur ini memiliki tiga langkah: pertukaran kunci, penandatanganan, dan verifikasi.
Langkah 1: Pertukaran kunci (terjadi sekali)
Ketika Anda mengonfigurasi webhook dengan platform seperti Stripe atau GitHub, mereka menghasilkan
kunci webhook dan menunjukkannya kepada Anda sekali. Anda menyimpannya di sisi server (tidak pernah di kode sisi klien atau repositori publik). Itu saja — kunci tidak pernah dikirim lagi melalui jaringan. Langkah 2: Pengirim menandatangani payload
Sebelum mengirimkan webhook, platform menghitung tanda tangan HMAC atas tubuh permintaan mentah menggunakan kunci bersama Anda:
Tanda tangan ini kemudian ditambahkan ke permintaan, biasanya dalam header seperti
signature = HMAC-SHA256(secret_key, request_body)
(GitHub) atau X-Hub-Signature-256 (Stripe). Tubuh payload bergerak tanpa perubahan. Stripe-Signature Langkah 3: Anda memverifikasi saat menerima
Ketika server Anda menerima webhook, Anda menghitung HMAC yang sama menggunakan tubuh mentah dan kunci yang disimpan, lalu membandingkannya dengan tanda tangan di header. Jika keduanya cocok, payload tersebut autentik dan tidak diubah. Jika tidak, tolak permintaan tersebut.
perbandingan waktu konstan
expected = HMAC-SHA256(your_secret, raw_body)
if not constant_time_equal(expected, header_signature):
return 401
Melihat — kita akan kembali ke alasan mengapa ini penting. header yang mengandung waktu dan satu atau lebih tanda tangan:
untuk pratinjau.
Stripe
Stripe mengirimkan header Stripe-Signature Tanda tangan dihitung atas
Stripe-Signature: t=1679000000,v1=abc123...,v0=oldformat...
(dikonkatenasi dengan titik). Memasukkan waktu memungkinkan Stripe melindungi terhadap serangan replay — jika penyerang mencatat permintaan yang valid dan mengirimkannya kembali nanti, Anda dapat menolaknya karena waktu sudah terlalu tua. timestamp.payload GitHub mengirimkan header
GitHub
dalam format X-Hub-Signature-256 . Tanda tangan dihitung sebagai HMAC-SHA256 dari tubuh mentah menggunakan kunci webhook yang Anda konfigurasi di pengaturan repositori Anda. sha256=<hex_digest>Shopify menggunakan header
Shopify
dengan tanda tangan HMAC-SHA256 yang dienkripsi dalam Base64 — konsep yang sama, hanya dengan pengekodan yang berbeda. X-Shopify-Hmac-Sha256 Verifikasi dalam Kode
Berikut ini adalah bagaimana verifikasi terlihat di tiga bahasa umum. Pola yang sama identik — hanya perintah library yang berbeda.
Kesalahan yang Menghancurkan Keamanan
Ular piton
import hmac
import hashlib
def verify_webhook(secret: str, payload: bytes, signature_header: str) -> bool:
expected = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
received = signature_header.removeprefix("sha256=")
return hmac.compare_digest(expected, received)
Bahasa pemrograman Node.js
const crypto = require('crypto');
function verifyWebhook(secret, rawBody, signatureHeader) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
const received = signatureHeader.replace('sha256=', '');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(received)
);
}
PHP
function verifyWebhook(string $secret, string $rawBody, string $signatureHeader): bool {
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret);
return hash_equals($expected, $signatureHeader);
}
1. Menggunakan == daripada perbandingan waktu konstan
Perbandingan string standar (
) mempercepat proses segera saat menemukan ketidaksesuaian. Ini menciptakan==, ===saluran waktu samping : penyerang dapat mengukur berapa lama server Anda menolak tanda tangan yang berbeda. String yang memiliki prefix yang lebih panjang membutuhkan waktu sedikit lebih lama untuk ditolak. Dengan cukup permintaan, penyerang dapat menggunakan ini untuk membangun tanda tangan yang valid secara per byte.Selalu gunakan perbandingan waktu konstan:
di Node.js, hmac.compare_digest() dalam Python, crypto.timingSafeEqual() di PHP. hash_equals() 2. Memarsing tubuh sebelum verifikasi
HMAC dihitung atas
byte mentah dari tubuh permintaan. Jika Anda memarsing JSON terlebih dahulu lalu mengubahnya kembali, Anda mungkin mendapatkan urutan byte yang berbeda (urutan kunci yang berbeda, spasi, pengkodean). Selalu tangkap tubuh mentah sebelum parser tubuh di framework Anda mengaksesnya, lalu verifikasi terhadap yang tersebut. 3. Tidak memeriksa serangan replay
Permintaan yang ditandatangani secara valid berlaku selamanya — kecuali Anda memeriksa waktu. Jika platform mencakup waktu dalam skema tanda tangan (Stripe melakukannya; GitHub tidak), tolak permintaan yang waktu sudah lebih dari beberapa menit. Ini mencegah penyerang mencatat dan mengulang permintaan yang sah.
4. Menyimpan kunci secara langsung dalam kode sumber
Kunci webhook harus berada di variabel lingkungan atau manajer rahasia, tidak pernah disimpan dalam kontrol versi. Jika kunci bocor, penyerang dapat membuat payload palsu selamanya — sampai Anda mengganti kuncinya.
Apa yang Tidak Dilindungi oleh HMAC
HMAC membuktikan bahwa payload ditandatangani oleh seseorang yang memiliki kunci. Namun, ini
tidak melindungi terhadap: bukan Penggunaan pengirim yang terkompromi
- — jika infrastruktur penandatanganan Stripe terkompromi, peristiwa palsu tetap akan memiliki tanda tangan yang valid — kecuali Anda juga memverifikasi waktu atau nonce
- Serangan ulang Kerahasiaan
- — HMAC tidak mengenkripsi apa pun; payload bergerak dalam bentuk teks biasa (meskipun HTTPS menangani ini) Untuk kebanyakan integrasi webhook, HMAC atas HTTPS mencakup semua yang Anda butuhkan.
HMAC — Bagaimana Webhook Tahu Anda Tidak Menipu 2
Instal Ekstensi Kami
Tambahkan alat IO ke browser favorit Anda untuk akses instan dan pencarian lebih cepat
恵 Papan Skor Telah Tiba!
Papan Skor adalah cara yang menyenangkan untuk melacak permainan Anda, semua data disimpan di browser Anda. Lebih banyak fitur akan segera hadir!
Alat Wajib Coba
Lihat semua Pendatang baru
Lihat semuaMemperbarui: Kita alat terbaru ditambahkan pada 13 Juni 2026
