Hopp til innholdet

Teknikk · 7. november 2026 · 6 min lesing

Webhooks enkelt forklart: signatur, gjentakelse, sikkerhet

Hva en webhook er, hvordan den skiller seg fra API-oppslag og hvordan du håndterer signatur, gjentakelse og duplikater. Med curl og Node.

To veier i sammenligning: Ved API-oppslag spør systemet ditt gang på gang, ved webhook kaller avsenderen adressen din én gang så snart noe skjer
Grafikk: Whovisit · Se grafikken i stor størrelse

En webhook er en telefon i motsatt retning. I stedet for at systemet ditt spør en tjeneste hvert par minutter om noe har skjedd, kaller tjenesten en adresse hos deg så snart det skjer. Det sparer oppslag og leverer nyheter raskere. Til gjengjeld må du stille en mottaker til rådighet og sikre den. Denne artikkelen forklarer begge deler.

Webhook eller API-oppslag

API-oppslag (polling)Webhook
Hvem starter?Systemet dittAvsenderen
Når?Etter tidsplan, for eksempel hver timeSå snart en hendelse inntreffer
InnsatsOppslag også uten nyheterEn tilgjengelig mottaker nødvendig
Godt forRapporter, avstemming, ettersendingVarsling, videresending
RisikoForsinkelse til neste oppslagMeldingen går tapt hvis mottakeren ikke svarer

I praksis kombinerer mange begge deler: Webhooken melder hendelsen, API-et henter ved behov detaljene eller tetter hull etter et utfall.

Hvordan en levering forløper

  1. En hendelse inntreffer, for eksempel «betaling mottatt».
  2. Avsenderen sender en POST med JSON til adressen du har lagt inn (HTTPS).
  3. Mottakeren din kontrollerer signaturen, noterer meldingen og svarer raskt med en kode fra 2xx-området.
  4. Selve arbeidet gjør systemet ditt etterpå.

Trinn 3 er viktig. Stripe anbefaler i webhook-dokumentasjonen å returnere en 2xx-kode umiddelbart, før krevende logikk kjører som kan utløse en timeout. Den som først bokfører og så svarer, risikerer unødvendige gjentakelser.

Signatur: slik kontrollerer du opprinnelsen

Adressen din er offentlig tilgjengelig. Hvem som helst kunne altså sende oppdiktede meldinger til den. Derfor signerer seriøse avsendere hver melding med en felles hemmelighet. Vanlig er en HMAC med SHA-256 over innholdet, ofte sammen med et tidsstempel. GitHub beskriver fremgangsmåten slik: HMAC-SHA256 over innholdet, fremstilt heksadesimalt, med overskriften X-Hub-Signature-256. Sammenligningen skal skje med en funksjon med konstant kjøretid, slik at angripere ikke kan utlede noe av svartidene.

Viktige punkter for mottakeren din:

  • Bruk rått innhold. Beregn signaturen over de mottatte bytene, ikke over JSON som er serialisert på nytt. Allerede en annen linjeskift endrer signaturen.
  • Kontroller tidsstempelet. Stripe bruker et tidsstempel i signaturen og en standardtoleranse på fem minutter for å hindre gjentakelsesangrep. En toleranse på 0 slår av kontrollen.
  • Hold hemmeligheten hemmelig. Ikke i koden, ikke i repositoriet, men i en miljøvariabel eller et hvelv.

Åpen kildekode-retningslinjer for avsendere og mottakere samler initiativet Standard Webhooks. Hvordan hver leverandør konkret danner signaturen sin, står i leverandørens dokumentasjon.

Gjentakelser og dobbeltlevering

Svarer mottakeren din ikke eller med en feilkode, prøver avsenderen på nytt. Stripe gjentar for eksempel ifølge egen dokumentasjon med økende mellomrom i inntil tre dager. Andre leverandører har andre regler, noen slår av webhooken etter for mange feil. Av det følger:

  • Regn med duplikater. Den samme hendelsen kan komme flere ganger, selv om mottakeren din arbeider korrekt. Stripe peker uttrykkelig på dette.
  • Gjør behandlingen idempotent. Det betyr: Den som behandler den samme meldingen to ganger, skaper ikke et andre resultat. Lagre identifikatoren til hendelsen og hopp over det som er kjent.
  • Stol ikke på rekkefølgen. Hendelser kan komme byttet om. Kontroller ved tvil den aktuelle tilstanden via API.

Sikkerhet på begge sider

For mottakere: bare HTTPS, kontroller signatur og alder, begrens størrelsen på meldingen, utfør ingen kommandoer fra innholdet. Behandle innholdet som enhver inndata utenfra.

For avsendere som kaller kunders adresser: Den som tilbyr webhooks, kaller adresser som andre har lagt inn. Det er en klassisk vei for Server-Side Request Forgery. Angriperen legger inn en intern adresse. Serveren kaller den fra det beskyttede nettet. OWASP-beskrivelsen nevner som mål for eksempel interne tjenester og metadataadresser hos skyleverandører. Fornuftige beskyttelsestiltak:

  • bare tillate https://,
  • løse opp adressen ved innlegging og før hvert kall og avvise private, lokale og reserverte områder,
  • ikke følge omdirigeringer blindt,
  • sette korte tidsgrenser.

Eksempel: sende en testmelding med curl

Med curl og openssl kan du teste mottakeren din uten den ekte avsenderen. Skriptet sender en signert melding, slik en avsender med tidsstempel ville sendt den:

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"

Eksempel: en liten mottaker i Node.js

const http = require('http')
const crypto = require('crypto')
const GEHEIMNIS = process.env.WEBHOOK_GEHEIMNIS || 'test-geheimnis'
const gesehen = new Set() // i drift: database

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)

Mottakeren kontrollerer signatur og alder, hopper over kjente identifikatorer og svarer umiddelbart. For driften trenger du i tillegg HTTPS, en størrelsesgrense og en kø for viderebehandlingen.

Hvor webhooks er utbredt

Betalingstjenester, kodeplattformer og skjemaverktøy melder hendelser per webhook. Også besøkergjenkjenning kan det: Melder systemet en bedrift som besøker siden din, havner den direkte i et verktøy etter eget valg. Hvordan det fører inn i et salgssystem, viser Hente nettsidebesøk inn i CRM. Alternativet via oppslag beskriver Hvilke bedrifter besøker nettsiden min? 3 veier i oversikt. Hvilke data som flyter her, forklarer Hvordan fungerer bedriftsgjenkjenning? Teknikken i 6 trinn.

Ofte stilte spørsmål

Hva er forskjellen mellom webhook og API? Ved API spør systemet ditt, ved webhook melder avsenderen seg av seg selv. Begge deler lar seg kombinere.

Hva skjer hvis mottakeren min faller ut? De fleste avsendere gjentar leveringen over en viss periode. Hvor lenge og hvor ofte, står i leverandørens dokumentasjon. For hull bør du planlegge en avstemming via API.

Rekker det å kontrollere avsenderadressen? Nei. Avsenderadresser kan forfalskes og endrer seg. Pålitelig er bare signaturen med en hemmelighet som bare du og avsenderen kjenner.

Les videre