\Drupal\strata\Event\Webhook WebhookSignature

Signs and verifies a webhook body.

The signature covers the timestamp AND the body, joined by a separator that cannot appear in the timestamp. Signing the body alone would let anyone who captured one delivery replay it forever; signing them concatenated without a separator would let a body starting with digits be traded against the timestamp for the same digest.

Verification is constant-time and bounded in age. A receiver that skipped the age check would accept a replay of a genuine delivery from any point in the past, which is the whole reason the timestamp is in the signed material.

Summary

Methods
Properties
Constants
sign
verify
No public properties found
HEADER
EVENT_HEADER
DELIVERY_HEADER
VERSION
DEFAULT_TOLERANCE
No protected methods found
No protected properties found
No protected constants found
payload
parse
No private properties found
ALGORITHM

Constant

HEADER

HEADER = 'X-Strata-Signature'

Header the signature travels in.

EVENT_HEADER

EVENT_HEADER = 'X-Strata-Event'

Header naming the event, so a receiver can route without parsing the body.

DELIVERY_HEADER

DELIVERY_HEADER = 'X-Strata-Delivery'

Header carrying the delivery id, so a receiver can drop a duplicate.

VERSION

VERSION = 'v1'

The scheme version, so a later algorithm can be told apart from this one.

DEFAULT_TOLERANCE

DEFAULT_TOLERANCE = 300

Seconds a signature stays acceptable.

ALGORITHM

ALGORITHM = 'sha256'

The digest algorithm.

Methods

sign()

sign(string  $body, string  $secret, int  $timestamp) : string

The header value for a body.

Parameters

string $body

The exact bytes that will be sent.

string $secret

The shared secret.

int $timestamp

Unix seconds the delivery was signed at.

Returns

string —

A header value of the form t=<unix>,v1=<hex>.

verify()

verify(string  $header, string  $body, string  $secret, int  $now, int  $tolerance = \self::DEFAULT_TOLERANCE) : bool

Whether a header value authenticates a body.

Parameters

string $header

The received header value.

string $body

The received body.

string $secret

The shared secret.

int $now

Unix seconds to measure age against.

int $tolerance

Seconds of age to accept.

Returns

bool —

TRUE when the signature matches and is inside the tolerance.

payload()

payload(string  $body, int  $timestamp) : string

The exact bytes the digest is taken over.

Parameters

string $body

The body.

int $timestamp

Unix seconds.

Returns

string —

The signed material.

parse()

parse(string  $header) : array{int, string}|null

Reads a header value.

Parameters

string $header

The header value.

Returns

array{int, string}|null —

The timestamp and the digest, or NULL when the header is not the expected shape.