feat(cookie): add AES-256-GCM encrypted cookie support#4818
feat(cookie): add AES-256-GCM encrypted cookie support#4818brunorodmoreira wants to merge 5 commits intohonojs:mainfrom
Conversation
Add serializeEncrypted and parseEncrypted to cookie utils using AES-256-GCM via Web Crypto API with HKDF-SHA256 key derivation.
Add setEncryptedCookie, getEncryptedCookie, generateEncryptedCookie with full prefix support and comprehensive test coverage.
- Use non-empty HKDF salt for stronger key derivation - Cache CryptoKey across multiple cookie decryptions - Bind ciphertext to cookie name via AES-GCM additional data (AAD) - Use loop-based base64 encoding to avoid stack overflow on large payloads - Wrap decodeURIComponent in try/catch for malformed cookie values
travisbreaks
left a comment
There was a problem hiding this comment.
Crypto implementation in a framework that runs on Cloudflare Workers deserves a careful look. Some observations:
-
IV uniqueness: 12 random bytes from
crypto.getRandomValues()is standard for AES-GCM and provides strong uniqueness guarantees. Good. -
HKDF salt: Is the salt hardcoded or configurable? If hardcoded, two different applications using the same master key would derive the same encryption key. A configurable salt (or using the cookie name as salt input) would provide domain separation.
-
AAD binding: If the cookie name is used as AAD (Additional Authenticated Data), this correctly prevents cookie swapping attacks (moving an encrypted value from cookie A to cookie B). Worth explicitly calling this out in the docs/comments if it is the case.
-
Workers shared isolate concern: CryptoKey objects cached across requests in Workers share the same isolate. This is fine for encryption keys derived from a static secret, but worth confirming the cache key includes all relevant derivation parameters so different configurations don't accidentally share a CryptoKey.
-
Timing side-channels: The base64 encoding/decoding path should be constant-time or at least not leak information about the plaintext length beyond what the ciphertext length already reveals. Standard
btoa/atobimplementations are generally fine here. -
Error handling: What happens if decryption fails (tampered ciphertext, wrong key)? AES-GCM will throw, and the behavior should be clearly documented: does it return
undefined, throw, or return the raw encrypted value?
Solid implementation overall. The main thing I'd want to see addressed is the salt configurability and the decryption failure behavior.
Closes #4817
Summary
setEncryptedCookie,getEncryptedCookie,generateEncryptedCookiehelpers using AES-256-GCM encryption via Web Crypto APIserializeEncrypted,parseEncryptedlow-level utils withEncryptedCookietypesetSignedCookie/getSignedCookie)Crypto design
crypto.subtle)base64(iv || ciphertext || authTag)The author should do the following, if applicable
bun run format:fix && bun run lint:fixto format the codeTest plan
undefinedfalsefalsefalse(AAD binding)generateEncryptedCookiewith and without options