webhook-id: 7c1e2f0a-3b5d-4e8f-9a61-2d4c8b0e5f13
webhook-timestamp: 1790490600
webhook-signature: v1,s0RzLJ1d7Cxd9nwe8pqER9DWy/stEIB+uT9MlGVLlM0=
| Glava |
Kaj je to |
| webhook-id |
Dostava, enaka vrednost kot delivery_id v telesu. Zapomnite si tiste, ki ste jih že obdelali, in na ponovitev odgovorite z 200, ne da bi delo opravili znova. |
| webhook-timestamp |
Čas, ko smo jo podpisali, v celih sekundah od leta 1970. Zavrnite vse, kar odstopa za več kot pet minut od vaše ure, da vam stare dostave ni mogoče poslati znova. |
| webhook-signature |
v1, nato base64 HMAC-SHA256 ID-ja, časovnega žiga in neobdelanega telesa, združenih s pikami, narejen z vašim podpisnim ključem. Lahko jih je več, ločenih s presledki. Sprejmite dostavo, če se ujema katerikoli od njih. |
Podpisni ključ
Začne se z whsec_. To odstranite in preostanek dekodirajte z base64: ti bajti so ključ HMAC, ne besedilo, ki ste ga kopirali. Prikaže se enkrat, ko povežete webhook ali na strani Publishing pritisnete "New signing key", in ga nikoli ne pošljemo.
Preverite neobdelano telo
Podpis izračunajte iz bajtov točno tako, kot so prispeli, preden jih karkoli razčleni. JSON, ki je bil dekodiran in znova kodiran, niso isti bajti in njegov podpis se ne bo ujemal.
PHP
<?php
$raw = getenv('SEONIS_SIGNING_KEY'); // whsec_...
// No key, no deliveries. A missing or empty variable would otherwise become
// an empty HMAC key, and anybody can sign with that.
$secret = is_string($raw) && str_starts_with($raw, 'whsec_')
? base64_decode(substr($raw, strlen('whsec_')), true)
: false;
if ($secret === false || strlen($secret) < 24) {
http_response_code(500);
exit('Signing key not configured.');
}
$id = $_SERVER['HTTP_WEBHOOK_ID'] ?? '';
$timestamp = $_SERVER['HTTP_WEBHOOK_TIMESTAMP'] ?? '';
$header = $_SERVER['HTTP_WEBHOOK_SIGNATURE'] ?? '';
$body = file_get_contents('php://input');
if (! ctype_digit($timestamp) || abs(time() - (int) $timestamp) > 300) {
http_response_code(401);
exit('Too old.');
}
$expected = base64_encode(hash_hmac('sha256', "$id.$timestamp.$body", $secret, true));
$valid = false;
foreach (explode(' ', $header) as $signature) {
[$version, $value] = array_pad(explode(',', $signature, 2), 2, '');
$valid = $valid || ($version === 'v1' && hash_equals($expected, $value));
}
if (! $valid) {
http_response_code(401);
exit('Bad signature.');
}
$delivery = json_decode($body, true);
Node.js
import crypto from 'node:crypto';
import express from 'express';
const app = express();
// No key, no server. An empty variable would otherwise become an empty HMAC
// key, and anybody can sign with that.
const raw = process.env.SEONIS_SIGNING_KEY ?? '';
if (!raw.startsWith('whsec_')) throw new Error('SEONIS_SIGNING_KEY is not set.');
const key = Buffer.from(raw.slice('whsec_'.length), 'base64');
if (key.length < 24) throw new Error('SEONIS_SIGNING_KEY is not a valid key.');
// express.raw keeps the body as the bytes we signed.
app.post('/hooks/seonis', express.raw({ type: 'application/json' }), (req, res) => {
const id = req.get('webhook-id') ?? '';
const timestamp = req.get('webhook-timestamp') ?? '';
const header = req.get('webhook-signature') ?? '';
if (!/^\d+$/.test(timestamp) || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
return res.status(401).send('Too old.');
}
const expected = crypto.createHmac('sha256', key)
.update(`${id}.${timestamp}.`)
.update(req.body)
.digest();
const valid = header.split(' ').some((signature) => {
const [version, value = ''] = signature.split(',');
const given = Buffer.from(value, 'base64');
return version === 'v1' && given.length === expected.length && crypto.timingSafeEqual(given, expected);
});
if (!valid) return res.status(401).send('Bad signature.');
const delivery = JSON.parse(req.body);
res.json({ ok: true });
});
Ali uporabite knjižnico
Uradne knjižnice Standard Webhooks za PHP, JavaScript, Python, Go, Ruby in druge vse to opravijo z enim klicem. Dajte jim podpisni ključ točno tako, kot vam je bil prikazan, vključno z whsec_.
github.com/standard-webhooks
Starejše glave
Dostave vsebujejo tudi podpisno skrivnost kot žeton bearer in X-AutoSEO-LT-Signature, HMAC samo telesa, narejen s to skrivnostjo. Še vedno ju pošiljamo, da končne točke, zgrajene na njiju, še naprej delujejo. Nova končna točka naj namesto tega preverja webhook-signature: stari podpis ne zajema časa niti ID-ja, njegov ključ pa se pošlje v vsakem zahtevku.
Oblike AutoSEO, Outrank in BabyLoveGrowth pošljejo točno to, kar so poslale te storitve, zato teh glav ne vsebujejo.