feat(cookie): RFC 6265bis cookie middleware#48
Merged
Merged
Conversation
RFC 6265/6265bis compliant cookie middleware with: - HMAC signing (sha256/sha384/sha512) with key rotation - AES-256-GCM encryption via Web Crypto API - Cookie prefix validation (__Host-, __Secure-) - Server-level cookie defaults with per-cookie overrides - Secure auto-detect (auto/true/false) - Auto prefix validation in serialize - SameSite=None+Secure enforcement - 400-day max lifetime validation - Cookie name RFC token validation - 4096-byte size limit enforcement - Zero node:crypto dependency (Bun.CryptoHasher + Web Crypto) - Monorepo resolve/validate pattern with @zipbul/result Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CookieJar: request-scoped container with get/set/delete/getSetCookieHeaders - get() returns ResultAsync (Err for tampered cookies, not throw) - set() auto sign+encrypt on getSetCookieHeaders - delete() queues maxAge:0 + expires:epoch - has() and getRaw() for existence check and third-party cookies - Remove parse/parseOne (Bun native wrappers with zero added value) - CookieParser: add isSigningConfigured/isEncryptionConfigured getters - Fix toErr string literal → CookieErrorReason enum - Integration/E2E tests rewritten with CookieJar Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…n defense - Partitioned cookies must have Secure attribute (CHIPS spec) - Domain/path header injection prevention (semicolons, newlines) - Bun Cookie constructor validates at construction time - CookieParser.serialize() validates as defense-in-depth - Tests verify both Bun-level and parser-level protection Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…validate Max-Age integer Closes 9 objective defects identified by RFC/NIST + functional verification: - C1: HMAC now signs (name + 0x00 + value) — prevents cross-cookie replay where a signature for cookie A could authenticate as cookie B. - C2: AES-GCM passes cookie name as AAD (NIST SP 800-38D §5.2.1) — same cross-name replay vector closed for encrypted cookies. - H1+N8: secrets and encryptionSecret enforced >= 32 chars (NIST SP 800-132). New WeakSecret reason rejects low-entropy inputs at create time. - H2: encryptionSecret accepts string | string[] for key rotation; decrypt iterates all keys, encrypt uses the first (current) key. - H3: HMAC verify loop is now constant-time — all secrets are verified, no early-exit. Position-based timing oracle closed (4.76x -> 1.03x measured). - M1: CookieJar.toErr accepts step name; non-CookieError fallback reports SignatureVerificationFailed for unsign failures vs DecryptionFailed. - N6+N7: Max-Age must be a finite integer (RFC 6265 §5.2.2). NaN, Infinity, decimals (0.5) now throw InvalidMaxAge in createCookie and serialize. Tests: 177 pass, 0 fail, 100% line + function coverage. Build: 10.76 KB ESM. Verified against real Chromium roundtrip. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Defects fixed (15):
- secure:'auto' no longer overrides explicit secure values (caller intent preserved via WeakMap meta)
- serialize() applies httpOnly/path/sameSite/partitioned defaults via createCookie
- Expires capped at 400 days (RFC 6265bis §5.5), not just Max-Age
- __Host- prefix rejects empty-string Domain
- createCookie strips null attribute values
- Domain validated against RFC 1034/1123 LDH
- name+value 4096-octet cap (RFC 6265bis §5.6) replaces total-header cap
- per-attribute 1024-octet cap added (RFC 6265bis §5.6)
- prefix detection case-insensitive (RFC 6265bis §5.7)
- single-label domains rejected; publicSuffixCheck hook for full PSL
- createCookie eager validation (Max-Age/Expires/Domain/Path/size)
- secret entropy verified (>= 8 distinct chars); message matches enforcement
- prefixValidation default flipped to true
- wrapBunError fallback uses dedicated CookieParserError reason
- CookieJar.delete() forces sameSite/secure overrides for unblocked deletion
Cryptographic hardening (8):
- HKDF-SHA256/384/512 key derivation (RFC 5869, NIST SP 800-108)
- 4-byte KID prefix in HMAC sigs and AES-GCM ciphertexts; strict KID match
- onEncrypt({keyIndex, counter}) IV-usage hook (NIST SP 800-38D §8.3)
- __Http- / __Host-Http- prefix validation (HttpOnly required)
- Priority=Low|Medium|High attribute support
- jar getSetCookieHeaders() parallelized via Promise.all
- per-instance HKDF-derived key cache
- test/{conformance,security,fuzz}/ tracked in source control
CookieErrorReason values normalized to kebab-case.
Breaking:
- HMAC sig + AES-GCM ciphertext wire formats changed (KID prefix)
- prefixValidation default false -> true
- entropy check rejects low-entropy secrets
- RFC 1123 Domain syntax enforced
- Path must start with "/"
Tests: 330 pass / 510 expects / 99.49% line coverage / 99.62% function coverage.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
# Conflicts: # bun.lock
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cookie middleware package with RFC 6265bis conformance and security hardening.