-
Notifications
You must be signed in to change notification settings - Fork 592
Description
🧭 Epic
Title: End-to-End JWS/HMAC Signing for Requests & Responses
Goal: Require every inbound request (and optionally every outbound response) to carry a verifiable signature; reject anything unsigned or tampered.
Why now: Spoofed calls & replay attacks are a real threat-signatures provide provenance, integrity, and non-repudiation.
🧭 Type of Feature
- Security hardening
- New functionality (experimental)
🙋♂️ User Story 1 - Verify Incoming Signatures
As a: Gateway
I want: to verify JWS signatures using server-side public keys
So that: only authentic, unmodified requests are processed.
✅ Acceptance Criteria
Scenario: Reject invalid JWS
Given gateway has keyset K
And receives POST /rpc signed with unknown key
Then respond 401 "signature_unknown"
And MUST NOT dispatch the RPC🙋♂️ User Story 2 - Sign Outbound Responses
As a: API consumer
I want: every response body JWS-signed by the gateway's private key
So that: clients can assert the response is genuine and untampered in transit.
✅ Acceptance Criteria
Scenario: Validate response signature
Given client holds gateway's public key
When it receives JSON-RPC result with `X-Signature`
Then cryptographic verification MUST succeed🙋♂️ User Story 3 - Replay-Attack Defense
As a: Security engineer
I want: each request to include a nonce & timestamp checked against an LRU cache
So that: attackers cannot replay a captured signed message.
✅ Acceptance Criteria
Scenario: Detect replayed nonce
Given nonce "abc123" was seen within 5 min window
When a second request arrives with same nonce
Then respond 409 "replay_detected"📐 Design Sketch
sequenceDiagram
participant C as Client
participant G as Gateway
C->>G: JWS({jsonrpc,id,method,nonce,ts})
G->>G: Verify sig & freshness
G-->>C: JWS({result}, headers:{X-Signature})
| Component | Change | Detail |
|---|---|---|
crypto_signature.py |
NEW | JWS/HMAC verify & sign helpers |
| Middleware | NEW | SignatureVerifier, SignatureSigner |
nonce_cache |
NEW | In-memory + Redis backend |
| Config | ADD | TRUSTED_KEYS, SIGN_RESPONSES, NONCE_TTL |
🔄 Roll-out Plan
- Phase 0: Generate keypair; publish gateway public key at
/.well-known/jwks.json. - Phase 1: Accept either signed or unsigned; log unsigned traffic.
- Phase 2: Require signatures for POST /rpc in staging; optional for responses.
- Phase 3: Enforce on all routes; enable response-signing flag; rotate keys annually.
📝 Spec-Draft Clauses
- Integrity - "Requests MUST carry a detached JWS (RFC 7515) over the canonical JSON body."
- Freshness - "Implementations MUST reject any nonce replayed within NONCE_TTL seconds."
- Response Signing - "Servers SHOULD sign responses; clients MAY require it."
📣 Next Steps
- Draft JWS canonicalization rules (JSON-Canonicalization Scheme).
- Implement nonce LRU cache prototype.
- Write conformance tests in
tests/crypto/.