Signed requests: strictly increasing timestamps per key
CI / Node 22 (push) Successful in 13s
CI / Node 24 (push) Successful in 13s
CI / Node 26 (push) Successful in 14s
CI / Node 24 (pull_request) Successful in 12s
CI / Chromium (pull_request) Successful in 48s
CI / Publish to staging registry (pull_request) Skipped
CI / Node 22 (pull_request) Successful in 13s
CI / Node 26 (pull_request) Successful in 12s
CI / Chromium (push) Successful in 47s
CI / Publish to staging registry (push) Successful in 10s
CI / Node 22 (push) Successful in 13s
CI / Node 24 (push) Successful in 13s
CI / Node 26 (push) Successful in 14s
CI / Node 24 (pull_request) Successful in 12s
CI / Chromium (pull_request) Successful in 48s
CI / Publish to staging registry (pull_request) Skipped
CI / Node 22 (pull_request) Successful in 13s
CI / Node 26 (pull_request) Successful in 12s
CI / Chromium (push) Successful in 47s
CI / Publish to staging registry (push) Successful in 10s
Ed25519 signatures are deterministic, so two identical requests from one key in the same millisecond (e.g. two devices subscribing to the same path, or parallel identical reads) had the same signature, and the server rejected the second as a replay. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Qxbkp4tA7G5SCWjzWuxmE
This commit is contained in:
@@ -137,6 +137,11 @@ development and tests). It can't be left open by omission.
|
||||
(unknown → 401) and checks the timestamp is within `maxSkewMs` (default 60 s). It then rejects a
|
||||
signature already accepted within that window (replay protection), and verifies the signature
|
||||
over the received path and raw body. The body is parsed only afterwards.
|
||||
- **Unique timestamps.** Ed25519 signatures are deterministic, so identical requests in the same
|
||||
millisecond would carry the same signature and the second would be rejected as a replay.
|
||||
`RequestAuth.headers` makes timestamps strictly increase per public key within a process. Two
|
||||
processes (e.g. browser tabs) with the same key can still collide, rarely; a nonce in the
|
||||
payload would fix that but changes the signing scheme.
|
||||
- **Algorithms are pluggable.** Built in: `Ed25519Signer` / `Ed25519Verifier` (WebCrypto, so no
|
||||
dependencies; Node 22+ and current browsers; keys persist as PKCS #8). Others, e.g. secp256k1 via
|
||||
libauth, implement `RequestSigner` (`algorithm`, `publicKey`, `sign`) and `SignatureVerifier`
|
||||
|
||||
Reference in New Issue
Block a user