Hoppa till innehållet

Teknik · 7 november 2026 · 5 min läsning

Webhooks enkelt förklarat: signatur, återförsök, säkerhet

Vad en webhook är, hur den skiljer sig från API-frågor och hur du hanterar signatur, återförsök och dubbletter. Med curl och Node.

Två vägar i jämförelse: Vid API-frågan frågar ditt system om och om igen, vid webhooken anropar avsändaren din adress en gång så fort något händer
Grafik: Whovisit · Visa grafiken i stor storlek

En webhook är ett samtal åt andra hållet. I stället för att ditt system hos en tjänst med några minuters mellanrum frågar om något har hänt anropar tjänsten en adress hos dig så fort det händer. Det sparar frågor och levererar nyheter snabbare. I gengäld måste du tillhandahålla och skydda en mottagare. Den här artikeln förklarar båda delarna.

Webhook eller API-fråga

API-fråga (polling)Webhook
Vem startar?Ditt systemAvsändaren
När?Enligt tidsplan, till exempel varje timmeSå fort en händelse inträffar
ArbetsinsatsFrågor även utan nyheterEn nåbar mottagare behövs
Bra förRapporter, avstämning, efterladdningAvisering, vidarebefordran
RiskFördröjning till nästa frågaMeddelandet går förlorat om mottagaren inte svarar

I praktiken kombinerar många båda: Webhooken meddelar händelsen, API:et hämtar vid behov detaljerna eller täcker luckor efter ett avbrott.

Hur en leverans går till

  1. En händelse inträffar, till exempel „Betalning mottagen“.
  2. Avsändaren skickar en POST med JSON till din angivna adress (HTTPS).
  3. Din mottagare kontrollerar signaturen, noterar meddelandet och svarar snabbt med en kod ur 2xx-området.
  4. Det egentliga arbetet utför ditt system efteråt.

Steg 3 är viktigt. Stripe rekommenderar i webhook-dokumentationen att omedelbart returnera en 2xx-kod innan krävande logik körs som kan utlösa en timeout. Den som först bokför fakturan och sedan svarar riskerar onödiga återförsök.

Signatur: så kontrollerar du ursprunget

Din adress är offentligt nåbar. Vem som helst kunde alltså skicka påhittade meddelanden till den. Därför signerar seriösa avsändare varje meddelande med en gemensam hemlighet. Vanligt är en HMAC med SHA-256 över innehållet, ofta tillsammans med en tidsstämpel. GitHub beskriver förfarandet så: HMAC-SHA256 över innehållet, hexadecimalt återgivet, med huvudraden X-Hub-Signature-256. Jämförelsen ska ske med en funktion med konstant körtid, så att angripare inte kan utläsa något ur svarstiderna.

Viktiga punkter för din mottagare:

  • Använd råinnehållet. Beräkna signaturen över de mottagna byten, inte över den på nytt serialiserade JSON-koden. Redan en annan radbrytning ändrar signaturen.
  • Kontrollera tidsstämpeln. Stripe använder en tidsstämpel i signaturen och en standardtolerans på fem minuter för att förhindra upprepningsattacker. En tolerans på 0 stänger av kontrollen.
  • Håll hemligheten hemlig. Inte i koden, inte i förvaret, utan i en miljövariabel eller ett kassaskåp.

Öppna riktlinjer för avsändare och mottagare samlar initiativet Standard Webhooks. Hur varje leverantör konkret bildar sin signatur står i dennes dokumentation.

Återförsök och dubbel leverans

Svarar din mottagare inte eller med en felkod försöker avsändaren igen. Stripe upprepar enligt egen dokumentation med växande intervall i upp till tre dagar. Andra leverantörer har andra regler, vissa stänger av webhooken efter för många misslyckanden. Därav följer:

  • Räkna med dubbletter. Samma händelse kan komma flera gånger, även om din mottagare arbetar korrekt. Stripe påpekar det uttryckligen.
  • Gör behandlingen idempotent. Det betyder: Den som behandlar samma meddelande två gånger skapar inget andra resultat. Lagra händelsens identifierare och hoppa över det som redan är känt.
  • Förlita dig inte på ordningsföljden. Händelser kan komma i ombytt ordning. Kontrollera vid tvivel det aktuella tillståndet via API.

Säkerhet på båda sidor

För mottagare: bara HTTPS, kontrollera signatur och ålder, begränsa meddelandets storlek, kör inga kommandon ur innehållet. Behandla innehållet som varje inmatning utifrån.

För avsändare som anropar kunders adresser: Den som erbjuder webhooks anropar adresser som andra har angett. Det är en klassisk väg för Server-Side Request Forgery. Angriparen anger en intern adress. Servern anropar den inifrån det skyddade nätet. OWASP:s beskrivning nämner som mål till exempel interna tjänster och metadataadresser hos molnleverantörer. Rimliga skyddsåtgärder:

  • tillåt bara https://,
  • lös upp adressen vid angivandet och före varje anrop och avvisa privata, lokala och reserverade områden,
  • följ inte omdirigeringar blint,
  • sätt korta tidsgränser.

Exempel: skicka ett testmeddelande med curl

Med curl och openssl kan du testa din mottagare utan den verkliga avsändaren. Skriptet skickar ett signerat meddelande, som en avsändare med tidsstämpel skulle skicka det:

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"

Exempel: en liten mottagare i Node.js

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

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)

Mottagaren kontrollerar signatur och ålder, hoppar över kända identifierare och svarar direkt. För driften behöver du dessutom HTTPS, en storleksbegränsning och en kö för vidarebehandlingen.

Var webhooks är vanliga

Betaltjänster, kodplattformar och formulärverktyg meddelar händelser via webhook. Också besöksigenkänning kan det: Meddelar systemet ett företag som besöker din sida hamnar det direkt i ett verktyg som du själv väljer. Hur det leder in i ett säljsystem visar Föra in webbplatsbesök i CRM. Alternativet via fråga beskriver Vilka företag besöker min webbplats?. Vilka data som flödar därvid förklarar Hur fungerar företagsigenkänning?.

Vanliga frågor

Vad är skillnaden mellan webhook och API? Vid API:et frågar ditt system, vid webhooken hör avsändaren av sig själv. Båda går att kombinera.

Vad händer om min mottagare går ner? De flesta avsändare upprepar leveransen under en viss tid. Hur länge och hur ofta står i leverantörens dokumentation. För luckor bör du planera en avstämning via API.

Räcker det att kontrollera avsändaradressen? Nej. Avsändaradresser går att förfalska och ändras. Pålitlig är bara signaturen med en hemlighet som bara du och avsändaren känner till.

Läs vidare