Preskoči na sadržaj

Tehnika · 7. studenoga 2026. · 5 min čitanja

Webhookovi jednostavno objašnjeni: potpis, ponavljanje, sigurnost

Što je webhook, po čemu se razlikuje od API upita i kako postupati s potpisom, ponavljanjem i duplikatima. S curlom i Nodeom.

Dva puta u usporedbi: kod API upita Vaš sustav stalno ponovno pita, kod webhooka pošiljatelj jednom poziva Vašu adresu čim se nešto dogodi
Grafika: Whovisit · Prikaži grafiku u punoj veličini

Webhook je poziv u suprotnom smjeru. Umjesto da Vaš sustav svakih nekoliko minuta pita neku uslugu je li se nešto dogodilo, usluga poziva adresu kod Vas čim se to dogodi. To štedi upite i brže donosi novosti. Zauzvrat morate osigurati primatelja i zaštititi ga. Ovaj članak objašnjava oboje.

Webhook ili API upit

API upit (polling)Webhook
Tko započinje?Vaš sustavPošiljatelj
Kada?Prema rasporedu, primjerice svaki satČim nastupi događaj
TrudUpiti i bez novostiPotreban dostupan primatelj
Dobro zaIzvješća, usklađivanje, naknadno učitavanjeObavijesti, prosljeđivanje
RizikKašnjenje do sljedećeg upitaPoruka se gubi ako primatelj ne odgovori

U praksi mnogi kombiniraju oboje: webhook prijavljuje događaj, a API po potrebi dohvaća pojedinosti ili zatvara rupe nakon ispada.

Kako teče isporuka

  1. Nastupi događaj, primjerice „uplata je stigla“.
  2. Pošiljatelj šalje POST s JSON-om na Vašu pohranjenu adresu (HTTPS).
  3. Vaš primatelj provjerava potpis, pamti poruku i brzo odgovara kodom iz raspona 2xx.
  4. Pravi posao Vaš sustav obavlja nakon toga.

Korak 3 je važan. Stripe u dokumentaciji o webhookovima preporučuje da se odmah vrati kod 2xx prije nego što se pokrene složena logika koja bi mogla izazvati istek vremena. Tko prvo knjiži račun, a tek onda odgovara, riskira nepotrebna ponavljanja.

Potpis: kako provjeriti podrijetlo

Vaša je adresa javno dostupna. Svatko bi joj dakle mogao slati izmišljene poruke. Zato ozbiljni pošiljatelji svaku poruku potpisuju zajedničkom tajnom. Uobičajen je HMAC sa SHA-256 preko sadržaja, često zajedno s vremenskom oznakom. GitHub opisuje postupak ovako: HMAC-SHA256 preko sadržaja, prikazan heksadecimalno, sa zaglavljem X-Hub-Signature-256. Usporedba se treba obaviti funkcijom s konstantnim trajanjem kako napadači iz vremena odgovora ne bi mogli ništa zaključiti.

Važne točke za Vašeg primatelja:

  • Koristiti sirovi sadržaj. Potpis izračunajte preko primljenih bajtova, a ne preko ponovno serijaliziranog JSON-a. Već i drugačiji prijelom retka mijenja potpis.
  • Provjeriti vremensku oznaku. Stripe koristi vremensku oznaku u potpisu i zadanu toleranciju od pet minuta kako bi spriječio napade ponavljanjem. Tolerancija 0 isključuje provjeru.
  • Tajnu držati tajnom. Ne u kodu, ne u repozitoriju, nego u varijabli okruženja ili trezoru.

Smjernice otvorenog koda za pošiljatelje i primatelje okuplja inicijativa Standard Webhooks. Kako svaki pružatelj konkretno gradi svoj potpis, stoji u njegovoj dokumentaciji.

Ponavljanja i dvostruka isporuka

Ako Vaš primatelj ne odgovori ili odgovori kodom pogreške, pošiljatelj pokušava ponovno. Stripe, primjerice, prema vlastitoj dokumentaciji ponavlja s rastućim razmacima do tri dana. Drugi pružatelji imaju druga pravila, neki isključuju webhook nakon previše neuspjeha. Iz toga slijedi:

  • Računajte s duplikatima. Isti događaj može stići više puta, čak i kad Vaš primatelj radi ispravno. Stripe na to izričito upozorava.
  • Obradu učinite idempotentnom. To znači: tko istu poruku obradi dvaput, ne stvara drugi rezultat. Pohranite oznaku događaja i preskočite poznato.
  • Ne oslanjajte se na redoslijed. Događaji mogu stići zamijenjenim redoslijedom. U slučaju sumnje provjerite aktualno stanje putem API-ja.

Sigurnost na obje strane

Za primatelje: samo HTTPS, provjeriti potpis i starost, ograničiti veličinu poruke, ne izvršavati naredbe iz sadržaja. Sadržaj tretirajte kao svaki ulaz izvana.

Za pošiljatelje koji pozivaju adrese klijenata: tko nudi webhookove, poziva adrese koje su unijeli drugi. To je klasičan put za Server-Side Request Forgery. Napadač unese internu adresu. Poslužitelj je poziva iz zaštićene mreže. OWASP-ov opis kao ciljeve navodi primjerice interne usluge i adrese metapodataka pružatelja oblaka. Smislene zaštitne mjere:

  • dopustiti samo https://,
  • adresu razriješiti pri unosu i prije svakog poziva te odbiti privatne, lokalne i rezervirane raspone,
  • ne slijediti preusmjeravanja naslijepo,
  • postaviti kratka vremenska ograničenja.

Primjer: slanje probne poruke curlom

Pomoću curla i openssla možete testirati svog primatelja bez pravog pošiljatelja. Skripta šalje potpisanu poruku kakvu bi poslao pošiljatelj s vremenskom oznakom:

GEHEIMNIS="test-geheimnis"
ZEIT=$(date +%s)
INHALT='{"id":"evt_1","typ":"besuch.begonnen","firma":"beispiel-firma.example"}'
SIGNATUR="sha256=$(printf '%s.%s' "$ZEIT" "$INHALT" | openssl dgst -sha256 -hmac "$GEHEIMNIS" | sed 's/^.* //')"

curl -X POST http://localhost:3000/webhook \
  -H "Content-Type: application/json" \
  -H "X-Zeit: $ZEIT" \
  -H "X-Signatur: $SIGNATUR" \
  -d "$INHALT"

Primjer: mali primatelj u Node.js-u

const http = require('http')
const crypto = require('crypto')
const GEHEIMNIS = process.env.WEBHOOK_GEHEIMNIS || 'test-geheimnis'
const gesehen = new Set() // u stvarnosti: baza podataka

http.createServer((req, res) => {
  if (req.method !== 'POST' || req.url !== '/webhook') { res.writeHead(404); return res.end() }
  const teile = []
  req.on('data', t => teile.push(t))
  req.on('end', () => {
    const roh = Buffer.concat(teile).toString('utf8')
    const zeit = req.headers['x-zeit'] || ''
    const erwartet = 'sha256=' + crypto.createHmac('sha256', GEHEIMNIS).update(zeit + '.' + roh).digest('hex')
    const erhalten = String(req.headers['x-signatur'] || '')
    const a = Buffer.from(erwartet), b = Buffer.from(erhalten)
    const echt = a.length === b.length && crypto.timingSafeEqual(a, b)
    const frisch = Math.abs(Date.now() / 1000 - Number(zeit)) < 300
    if (!echt || !frisch) { res.writeHead(401); return res.end() }
    const ereignis = JSON.parse(roh)
    if (!gesehen.has(ereignis.id)) { gesehen.add(ereignis.id); console.log('neu:', ereignis.typ) }
    res.writeHead(200); res.end('ok')
  })
}).listen(3000)

Primatelj provjerava potpis i starost, preskače poznate oznake i odmah odgovara. Za pogon dodatno trebate HTTPS, ograničenje veličine i red čekanja za daljnju obradu.

Gdje su webhookovi rašireni

Platne usluge, platforme za kod i alati za obrasce javljaju događaje webhookom. To može i prepoznavanje posjetitelja: ako sustav prijavi tvrtku koja posjećuje Vašu stranicu, ona odmah završava u alatu po Vašem izboru. Kako to vodi u prodajni sustav, pokazuje Kako posjete web stranici dovesti u CRM. Alternativu putem upita opisuje Koje tvrtke posjećuju moju web stranicu?. Koji podaci pritom teku, objašnjava Kako funkcionira prepoznavanje tvrtki?.

Često postavljana pitanja

Koja je razlika između webhooka i API-ja? Kod API-ja Vaš sustav pita, kod webhooka se pošiljatelj sam javlja. Oboje se može kombinirati.

Što se događa ako moj primatelj ispadne? Većina pošiljatelja ponavlja isporuku tijekom određenog razdoblja. Koliko dugo i koliko često, stoji u dokumentaciji pružatelja. Za rupe biste trebali planirati usklađivanje putem API-ja.

Je li dovoljno provjeriti adresu pošiljatelja? Ne. Adrese pošiljatelja mogu se lažirati i mijenjaju se. Pouzdan je samo potpis s tajnom koju znate samo Vi i pošiljatelj.

Čitaj dalje