Tidak suka iklan? Pergi Bebas Iklan Hari ini

Universitas Teknologi Hannover Bagaimana Webhook Mengetahui Kamu Tidak Berbohong

Diterbitkan pada

Setiap kali GitHub, Stripe, atau Shopify mengirimkan webhook ke server Anda, mereka menandatangani payload dengan HMAC. Berikut cara kerjanya — dan cara memverifikasinya dalam kode Anda.

HMAC: Bagaimana Webhook Mengetahui Kamu Tidak Berbohong
IKLAN · HAPUS?

Kamu menerima permintaan POST yang mengklaim berasal dari Stripe. Isi payload menyatakan pembayaran berhasil. Kamu memproses pesanan, mengirimkan barang — dan tiga hari kemudian kamu menemukan permintaan tersebut dirancang palsu. Ouch.

Ini adalah alasan mengapa setiap penyedia webhook serius menandatangani payload mereka menggunakan Universitas Teknologi Hannover. Jika kamu memahami HMAC, maka kamu memahami mengapa GitHub, Stripe, Shopify, Twilio, dan hampir semua API modern menggunakan hal ini — dan kamu tahu persis cara memverifikasi tanda tangan tersebut di kode servermu sendiri.

Apa sebenarnya HMAC

HMAC berarti Kode Autentikasi Pesan Berbasis Hash. Ini menjawab satu pertanyaan: "Apakah pihak yang mengirimkan pesan ini tahu rahasia bersama yang digunakan?"

Ini bekerja dengan menjalankan fungsi hash kriptografi — biasanya SHA-256 — atas kombinasi kunci rahasia dan isi pesan. Outputnya adalah string dengan panjang tetap yang:

  • berubah secara total jika satu saja byte dari pesan berubah
  • tidak bisa dihasilkan tanpa tahu kunci rahasia
  • tidak bisa dibalikkan untuk mengungkapkan kunci atau pesan aslinya

Rumusnya ringkas: HMAC(key, message) = H((key ⊕ opad) || H((key ⊕ ipad) || message)). Kamu tidak perlu menghafal bagian internal — setiap bahasa memiliki implementasi standar di library — tetapi penting untuk memahami maksudnya: kunci dicampurkan ke hash dua kali, dengan cara yang berbeda, untuk mencegah serangan jenis panjang-ekstensi.

Cara penyedia webhook menggunakan ini

Ketika kamu mendaftarkan endpoint webhook, penyedia memberimu sebuah kunci tanda tangan — sebuah string acak yang hanya kamu dan mereka tahu. Ketika peristiwa terjadi:

  1. Penyedia menyusun payload peristiwa ke dalam JSON (atau string standar).
  2. Lalu menghitung HMAC-SHA256(secret, payload).
  3. Lalu mengirimkan permintaan dengan tanda tangan di header — X-Hub-Signature-256 untuk GitHub, Stripe-Signature untuk Stripe, dan seterusnya.

Di pihak kamu, kamu melakukan perhitungan yang sama terhadap tubuh permintaan asli dan membandingkannya. Jika hasilnya cocok, payload tersebut autentik. Jika tidak, abaikan.

Pemeriksaan dalam kode

Berikut ini adalah contoh pemeriksaan yang umum digunakan di bahasa pemrograman yang paling umum. Pola yang sama ditemukan di semua bahasanya: hitung, bandingkan dengan fungsi waktu konstan.

Bahasa pemrograman Node.js

const crypto = require('crypto');

function verifyWebhook(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)          // rawBody must be a Buffer or string — NOT parsed JSON
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

Ular piton

import hmac
import hashlib

def verify_webhook(raw_body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        raw_body,
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(expected, signature)

PHP

function verifyWebhook(string $rawBody, string $signature, string $secret): bool {
    $expected = hash_hmac('sha256', $rawBody, $secret);
    return hash_equals($expected, $signature);
}

Detail pentingnya: gunakan tubuh asli

Kesalahan paling umum dalam implementasi adalah mengirimkan payload yang sudah diproses dan dire-serialisasi ke fungsi HMAC alih-alih byte asli. Urutan kunci, spasi, dan penggantian Unicode semua memengaruhi hash. Penyedia menandatangani tepatnya byte yang dikirimkan melalui kabel — kamu harus menghitung hash dari byte yang sama.

Dalam Express (Node.js), artinya adalah mengatur parser tubuh agar menyimpan buffer asli:

app.use('/webhooks', express.raw({ type: 'application/json' }));

Dalam Django, gunakan request.body alih-alih request.data. Dalam Flask, gunakan request.get_data().

Mengapa tidak cukup menggunakan hash biasa?

Hash SHA-256 biasa dari payload tidak membuktikan apa-apa — siapa pun bisa menghitungnya tanpa rahasia. Kunci rahasia HMAC yang membuatnya menjadi sebuah SHA256(payload) kode, bukan hanya checksum. Ini menjawab "siapa yang mengirimkan ini" daripada hanya "apakah pesan ini rusak saat perjalanan." autentikasi Mengapa tidak menggunakan tanda tangan asimetris (seperti RSA)?

RSA dan ECDSA memungkinkan penerima untuk memverifikasi tanda tangan tanpa tahu kunci pribadi — ini berguna untuk distribusi umum (seperti penandatanganan kode). Untuk webhook, hanya dua pihak yang perlu memverifikasi tanda tangan: kamu dan penyedia. Kunci bersama lebih sederhana, lebih cepat, dan sama amannya dalam model ini. Beberapa penyedia (Svix, Clerk) juga menawarkan tanda tangan asimetris untuk webhook dalam kasus ketika kamu tidak bisa menyimpan kunci secara aman di server.

Serangan replay — dan cara menghentikannya

Tanda tangan HMAC yang valid membuktikan keaslian, tetapi tidak membuktikan kebaruan. Seorang penyerang yang menangkap permintaan yang sah dapat mempermainkannya kembali nanti. Stripe mengatasi ini dengan menyisipkan waktu dalam header dan menghitung waktu bersama dengan isi pesan. Di pihak kamu, kamu menolak semua permintaan yang waktu timestamp-nya lebih dari lima menit tua.

Jika kamu membangun sistem webhook sendiri, lakukan hal yang sama: sisipkan nonce yang meningkat secara monoton atau waktu Unix dalam pesan yang ditandatangani, dan tolak permintaan yang sudah kadaluwarsa di server. Stripe-Signature Pembandingan waktu yang aman tidak opsional

Jangan membandingkan tanda tangan HMAC dengan perbandingan biasa (

). Pembandingan string yang cepat akan membocorkan informasi tentang berapa banyak byte awal yang cocok — penyerang yang membuat ribuan permintaan dapat membangun tanda tangan yang diharapkan satu byte per satu byte. Selalu gunakan perbandingan waktu konstan:

PHP:===, ==Go:

  • Node.js: crypto.timingSafeEqual()
  • Python: hmac.compare_digest()
  • Ruby: hash_equals()
  • Menggabungkan semuanya: handler webhook siap produksi hmac.Equal()
  • Berikut contoh lengkap menggunakan header GitHub di Node.js: ActiveSupport::SecurityUtils.secure_compare()

Referensi cepat: siapa yang menggunakan apa

Penyedia X-Hub-Signature-256 Waktu dalam tanda tangan?

const express = require('express');
const crypto = require('crypto');

const app = express();
const WEBHOOK_SECRET = process.env.GITHUB_WEBHOOK_SECRET;

// Keep the body as raw bytes — critical!
app.use('/github/webhook', express.raw({ type: 'application/json' }));

app.post('/github/webhook', (req, res) => {
  const sigHeader = req.headers['x-hub-signature-256'];
  if (!sigHeader) return res.status(401).send('Missing signature');

  const sig = sigHeader.replace('sha256=', '');
  const expected = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(req.body)
    .digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig))) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(req.body);
  // Safe to process the event now
  console.log('Event type:', req.headers['x-github-event']);

  res.sendStatus(200);
});

app.listen(3000);

X-Hub-Signature-256

Stripe-SignatureJudulAlgoritmaX-Shopify-Hmac-Sha256
GitHubX-Twilio-SignatureHMAC-SHA256TIDAK
StripeX-Slack-SignatureHMAC-SHA256Ya
ShopifyPaddleHMAC-SHA256TIDAK
TwilioPaddle-SignatureHMAC-SHA1TIDAK
KendurHMAC: Bagaimana Webhook Mengetahui Kamu Tidak Berbohong 2HMAC-SHA256Ya
HMAC: Bagaimana Webhook Mengetahui Kamu Tidak Berbohong 1Setiap kali GitHub, Stripe, atau Shopify mengirimkan webhook ke servermu, mereka menandatangani payload dengan HMAC. Ini adalah cara tepatnya — dan cara memverifikasinya di kode kamu sendiri.HMAC-SHA256Ya
Ingin bebas iklan? Bebas Iklan Hari Ini

Instal Ekstensi Kami

Tambahkan alat IO ke browser favorit Anda untuk akses instan dan pencarian lebih cepat

Ke Ekstensi Chrome Ke Ekstensi Tepi Ke Ekstensi Firefox Ke Ekstensi Opera

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!

IKLAN · HAPUS?
IKLAN · HAPUS?
IKLAN · HAPUS?

Pojok Berita dengan Sorotan Teknologi

Terlibat

Bantu kami untuk terus menyediakan alat gratis yang berharga

Belikan aku kopi
IKLAN · HAPUS?