webhook-id: 7c1e2f0a-3b5d-4e8f-9a61-2d4c8b0e5f13
webhook-timestamp: 1790490600
webhook-signature: v1,s0RzLJ1d7Cxd9nwe8pqER9DWy/stEIB+uT9MlGVLlM0=
| Galvene |
Kas tas ir |
| webhook-id |
Piegāde, tā pati vērtība, kas pamattekstā ir delivery_id. Atcerieties jau apstrādātās vērtības un uz atkārtotu piegādi atbildiet ar 200, neveicot darbu vēlreiz. |
| webhook-timestamp |
Laiks, kad mēs to parakstījām, pilnās sekundēs kopš 1970. gada. Noraidiet visu, kas atšķiras no jūsu pulksteņa par vairāk nekā piecām minūtēm, lai vecu piegādi nevarētu jums nosūtīt vēlreiz. |
| webhook-signature |
v1, pēc tam id, laika zīmoga un neapstrādātā pamatteksta base64 HMAC-SHA256, savienots ar punktiem un izveidots ar jūsu parakstīšanas atslēgu. To var būt vairāk nekā viens, atdalīti ar atstarpēm. Pieņemiet piegādi, ja sakrīt jebkurš no tiem. |
Parakstīšanas atslēga
Tā sākas ar whsec_. Noņemiet to un pārējo atkodējiet no base64: šie baiti ir HMAC atslēga, nevis teksts, ko nokopējāt. Tā tiek parādīta vienu reizi, kad pieslēdzat webhook vai Publishing lapā nospiežat "New signing key", un mēs to nekad nesūtām.
Pārbaudiet neapstrādāto pamattekstu
Aprēķiniet parakstu no baitiem tieši tādiem, kādi tie tika saņemti, pirms kaut kas tos parsē. JSON, kas ir atkodēts un atkal iekodēts, vairs nav tie paši baiti, un tā paraksts nesakritīs.
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 });
});
Vai izmantojiet bibliotēku
Oficiālās Standard Webhooks bibliotēkas PHP, JavaScript, Python, Go, Ruby un citām valodām to visu izdara ar vienu izsaukumu. Iedodiet tām parakstīšanas atslēgu tieši tā, kā tā jums tika parādīta, ieskaitot whsec_.
github.com/standard-webhooks
Vecākās galvenes
Piegādēs joprojām ir arī parakstīšanas slepenā vērtība kā bearer marķieris un X-AutoSEO-LT-Signature, kas ir tikai pamatteksta HMAC, izveidots ar šo slepeno vērtību. Tās joprojām tiek sūtītas, lai galapunkti, kas uz tām balstīti, turpinātu darboties. Jaunam galapunktam tā vietā jāpārbauda webhook-signature: vecais paraksts neietver ne laiku, ne id, un tā atslēga tiek sūtīta katrā pieprasījumā.
AutoSEO, Outrank un BabyLoveGrowth formāti sūta tieši to, ko nosūtīja šie pakalpojumi, tāpēc tajos nav šo galveņu.