# Webhooky jednoducho: podpis, opakovanie, bezpečnosť

> Čo je webhook, ako sa líši od dotazu API a ako zaobchádzať s podpisom, opakovaním a duplikátmi. S curl a Node.

Quelle: https://whovisit.app/sk/blog/webhooky-jednoducho-podpis-opakovanie
Veröffentlicht: 2026-11-07
Herausgeber: Whovisit (ARAVILO, Innsbruck)

Webhook je telefonát opačným smerom. Namiesto toho, aby sa váš systém každých pár minút pýtal služby, či sa niečo stalo, služba vyvolá adresu u vás, hneď ako sa to stane. Ušetrí to dotazy a novinky dodá rýchlejšie. Za to musíte poskytnúť príjemcu a zabezpečiť ho. Tento článok vysvetľuje oboje.

## Webhook alebo dotaz API

| | Dotaz API (polling) | Webhook |
|---|---|---|
| Kto začína? | Váš systém | Odosielateľ |
| Kedy? | Podľa harmonogramu, napríklad každú hodinu | Hneď ako nastane udalosť |
| Náročnosť | Dotazy aj bez noviniek | Potrebný dosiahnuteľný príjemca |
| Dobré na | Správy, zosúladenie, doplnenie | Upozornenie, preposielanie |
| Riziko | Oneskorenie do ďalšieho dotazu | Správa sa stratí, ak príjemca neodpovie |

V praxi mnohí kombinujú oboje: Webhook ohlási udalosť, API v prípade potreby stiahne podrobnosti alebo vyplní medzery po výpadku.

## Ako prebieha doručenie

1. Nastane udalosť, napríklad „platba prijatá“.
2. Odosielateľ pošle POST s JSON na vašu zadanú adresu (HTTPS).
3. Váš príjemca skontroluje podpis, zapamätá si správu a rýchlo odpovie kódom z rozsahu 2xx.
4. Vlastnú prácu potom vykoná váš systém.

Krok 3 je dôležitý. Stripe odporúča v [dokumentácii webhookov](https://docs.stripe.com/webhooks) okamžite vrátiť kód 2xx, skôr než sa spustí náročná logika, ktorá by mohla vyvolať timeout. Kto najprv zaúčtuje faktúru a potom odpovie, riskuje zbytočné opakovania.

## Podpis: ako skontrolovať pôvod

Vaša adresa je verejne dostupná. Ktokoľvek by na ňu teda mohol posielať vymyslené správy. Preto seriózni odosielatelia podpisujú každú správu spoločným tajomstvom. Bežný je HMAC so SHA-256 nad obsahom, často spolu s časovou pečiatkou. [GitHub opisuje postup](https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries) takto: HMAC-SHA256 nad obsahom, zobrazený hexadecimálne, v hlavičke `X-Hub-Signature-256`. Porovnanie má prebehnúť funkciou s konštantnou dobou behu, aby útočníci nemohli z časov odpovede nič odvodiť.

Dôležité body pre vášho príjemcu:

- **Použiť surový obsah.** Podpis vypočítajte nad prijatými bajtmi, nie nad znova serializovaným JSON. Už iný koniec riadku zmení podpis.
- **Skontrolovať časovú pečiatku.** Stripe používa v podpise časovú pečiatku a štandardnú toleranciu piatich minút, aby zabránil útokom opakovaním. Tolerancia 0 kontrolu vypína.
- **Tajomstvo držať v tajnosti.** Nie v kóde, nie v repozitári, ale v premennej prostredia alebo trezore.

Open source pokyny pre odosielateľov a príjemcov zlučuje iniciatíva [Standard Webhooks](https://www.standardwebhooks.com/). Ako konkrétne každý poskytovateľ tvorí svoj podpis, je v jeho dokumentácii.

## Opakovania a dvojité doručenie

Ak váš príjemca neodpovie alebo odpovie chybovým kódom, odosielateľ to skúsi znova. Stripe napríklad podľa vlastnej dokumentácie opakuje so stúpajúcimi odstupmi až tri dni. Iní poskytovatelia majú iné pravidlá, niektorí webhook po príliš veľa neúspechoch vypnú. Z toho vyplýva:

- **Počítajte s duplikátmi.** Tá istá udalosť môže prísť viackrát, aj keď váš príjemca pracuje správne. Stripe na to výslovne upozorňuje.
- **Spracúvanie urobte idempotentné.** To znamená: Kto tú istú správu spracuje dvakrát, nevytvorí druhý výsledok. Uložte identifikátor udalosti a známe preskočte.
- **Nespoliehajte sa na poradie.** Udalosti môžu prísť poprehadzované. V prípade pochybností skontrolujte aktuálny stav cez API.

## Bezpečnosť na oboch stranách

**Pre príjemcov:** len HTTPS, kontrolovať podpis a vek, obmedziť veľkosť správy, nevykonávať žiadne príkazy z obsahu. S obsahom zaobchádzajte ako s každým vstupom zvonka.

**Pre odosielateľov, ktorí vyvolávajú adresy zákazníkov:** Kto ponúka webhooky, vyvoláva adresy, ktoré zapísali iní. Je to klasická cesta pre Server-Side Request Forgery. Útočník zapíše internú adresu. Server ju vyvolá z chránenej siete. [Opis OWASP](https://community.owasp.org/attacks/Server_Side_Request_Forgery) uvádza ako ciele napríklad interné služby a metadátové adresy poskytovateľov cloudu. Zmysluplné ochranné opatrenia:

- povoliť len `https://`,
- adresu pri zápise a pred každým vyvolaním rozložiť a odmietnuť súkromné, lokálne a vyhradené rozsahy,
- nenasledovať presmerovania naslepo,
- nastaviť krátke časové limity.

## Príklad: odoslanie testovacej správy pomocou curl

S curl a openssl môžete otestovať svojho príjemcu bez skutočného odosielateľa. Skript pošle podpísanú správu, ako by ju poslal odosielateľ s časovou pečiatkou:

```bash
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"
```

## Príklad: malý príjemca v Node.js

```js
const http = require('http')
const crypto = require('crypto')
const GEHEIMNIS = process.env.WEBHOOK_GEHEIMNIS || 'test-geheimnis'
const gesehen = new Set() // v praxi: databáza

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)
```

Príjemca kontroluje podpis a vek, preskakuje známe identifikátory a odpovedá okamžite. Pre prevádzku navyše potrebujete HTTPS, obmedzenie veľkosti a frontu na ďalšie spracovanie.

## Kde sú webhooky rozšírené

Platobné služby, platformy pre kód a nástroje na formuláre ohlasujú udalosti cez webhook. Môže to aj rozpoznávanie návštevníkov: Ak systém ohlási firmu, ktorá navštívila vašu stránku, pristane priamo vo vami zvolenom nástroji. Ako to vedie do predajného systému, ukazuje [Dostať návštevy webu do CRM](https://whovisit.app/blog/website-besuche-ins-crm). Alternatívu cez dotaz opisuje [Ktoré firmy navštevujú môj web?](https://whovisit.app/blog/welche-firmen-besuchen-meine-website). Aké údaje pritom tečú, vysvetľuje [Ako funguje rozpoznávanie firiem?](https://whovisit.app/blog/firmenerkennung-website-technik).

## Časté otázky

**Aký je rozdiel medzi webhookom a API?** Pri API sa pýta váš systém, pri webhooku sa odosielateľ ohlási sám. Oboje sa dá kombinovať.

**Čo sa stane, ak môj príjemca vypadne?** Väčšina odosielateľov opakuje doručenie počas určitého obdobia. Ako dlho a ako často, je v dokumentácii poskytovateľa. Na medzery by ste mali naplánovať zosúladenie cez API.

**Stačí skontrolovať adresu odosielateľa?** Nie. Adresy odosielateľov sa dajú predstierať a menia sa. Spoľahlivý je len podpis s tajomstvom, ktoré poznáte len vy a odosielateľ.
