fix(commerce): harden demo server for public deployment#189
Merged
mohamedmansour merged 9 commits intomainfrom Apr 8, 2026
Merged
fix(commerce): harden demo server for public deployment#189mohamedmansour merged 9 commits intomainfrom
mohamedmansour merged 9 commits intomainfrom
Conversation
Security audit identified 7 findings; all are now resolved: 1. Security headers — Add DefaultHeaders middleware with CSP, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, and Permissions-Policy on every response (security.rs). 2. Cache-Control / Vary — Set 'Cache-Control: private, no-store' and 'Vary: Accept, Cookie' on all dynamic HTML and JSON responses to prevent CDN/proxy cache poisoning of personalized content. 3. CSRF protection — Validate Origin (or Referer) header on /cart/add and /cart/update POST endpoints. Rejects cross-origin requests with 403 while allowing same-origin form submissions and test harnesses that omit both headers (OWASP double-submit approach). 4. Rate limiting — Add in-memory IP-based fixed-window rate limiter (60 req/IP/min) stored in AppState. Applied to cart mutation endpoints. Returns 429 when exceeded. Fails open on missing peer IP. Expired entries pruned opportunistically. 5. Open redirect hardening — Reject backslashes, control characters (< 0x20), and DEL (0x7f) in sanitize_redirect() to close browser-dependent redirect edge cases. 6. HMAC cookie signing — Sign cart cookie with HMAC-SHA256 (hmac + sha2 crates). Cookie format is now '<hex_payload>.<hex_sig>'. Unsigned or tampered cookies are rejected and cart is reset. 7. Static asset cache headers — Add 'Cache-Control: public, max-age=86400' to CSS and asset responses in serve_asset(). New files: security.rs, rate_limit.rs, EXPLOIT.md (audit report). New deps: hmac 0.12, sha2 0.10 (MIT, passes cargo deny). All 40 tests pass (11 new tests across the security modules). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Hardens the commerce demo server for safer public deployment by adding standard security headers, preventing caching of personalized responses, adding CSRF checks and rate limiting on cart mutations, and signing cart cookies to prevent tampering.
Changes:
- Add security middleware (CSP + related headers), CSRF origin/referer validation, and IP-based rate limiting for cart mutation endpoints.
- Add cache headers for dynamic responses and static assets; tighten redirect sanitization.
- Sign cart cookies with HMAC-SHA256 and add an audit writeup documenting findings/resolutions.
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| examples/app/commerce/server/src/server.rs | Adds CSRF + rate-limit checks to cart mutations; adds Cache-Control/Vary to dynamic JSON/HTML responses. |
| examples/app/commerce/server/src/security.rs | Introduces security headers middleware and CSRF validation helpers + tests. |
| examples/app/commerce/server/src/rate_limit.rs | Adds in-memory fixed-window IP rate limiter + tests. |
| examples/app/commerce/server/src/main.rs | Wires security headers middleware and new modules into the server. |
| examples/app/commerce/server/src/frontend.rs | Adds Cache-Control for CSS and other static asset responses. |
| examples/app/commerce/server/src/error.rs | Adds CsrfRejected (403) and RateLimited (429) error variants. |
| examples/app/commerce/server/src/cart.rs | Adds redirect hardening and HMAC-signed cart cookie format + tests. |
| examples/app/commerce/server/src/app.rs | Stores RateLimiter in AppState and exposes accessor. |
| examples/app/commerce/server/Cargo.toml | Adds hmac/sha2 deps (workspace) for cookie signing. |
| examples/app/commerce/EXPLOIT.md | Adds security audit report describing the findings and fixes. |
| Cargo.toml | Adds a new workspace member and workspace deps for hmac/sha2. |
- Use constant-time HMAC verification via verify_slice instead of string equality for cookie signature checks - Fix CSRF to fail closed when Origin/Referer is present but Host header is missing, preventing validation bypass - Apply Cache-Control and Vary headers to both JSON and redirect response branches in cart mutations - Remove non-existent examples/benchmarks/teams/server workspace member - Add regression tests for CSRF Host-missing scenarios Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
9b264a7 to
66c9238
Compare
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
janechu
previously approved these changes
Apr 8, 2026
1. Constant-time HMAC verification — Replace string equality with hmac::verify_slice for timing-safe signature validation. 2. Runtime cookie secret — Move HMAC key from hardcoded constant to CART_COOKIE_SECRET env var via OnceLock. Falls back to ephemeral per-process key when unset. Dockerfile sets a default placeholder. 3. CSP nonce support — Replace 'unsafe-inline' for script-src with per-request nonces using the framework's existing RenderOptions .with_nonce() API. CSP header is now set per-response with the matching nonce value. 4. Cache headers on all cart responses — Move Cache-Control/Vary headers outside the JSON-only branch so redirect responses are also marked private/no-store. 5. Proxy-aware rate limiting — Add client_ip() helper that reads X-Forwarded-For before falling back to peer_addr(), so rate limiting works correctly behind Docker/CDN reverse proxies. 6. CSRF fail-closed — Reject requests when Origin or Referer is present but Host is missing (validation impossible). Only allow when all three headers are absent. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
janechu
approved these changes
Apr 8, 2026
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.
Security audit identified 7 findings; all are now resolved to make the demo site safer:
Security headers — Add DefaultHeaders middleware with CSP, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, and Permissions-Policy on every response (security.rs).
Cache-Control / Vary — Set 'Cache-Control: private, no-store' and 'Vary: Accept, Cookie' on all dynamic HTML and JSON responses to prevent CDN/proxy cache poisoning of personalized content.
CSRF protection — Validate Origin (or Referer) header on /cart/add and /cart/update POST endpoints. Rejects cross-origin requests with 403 while allowing same-origin form submissions and test harnesses that omit both headers (OWASP double-submit approach).
Rate limiting — Add in-memory IP-based fixed-window rate limiter (60 req/IP/min) stored in AppState. Applied to cart mutation endpoints. Returns 429 when exceeded. Fails open on missing peer IP. Expired entries pruned opportunistically.
Open redirect hardening — Reject backslashes, control characters (< 0x20), and DEL (0x7f) in sanitize_redirect() to close browser-dependent redirect edge cases.
HMAC cookie signing — Sign cart cookie with HMAC-SHA256 (hmac + sha2 crates). Cookie format is now '<hex_payload>.<hex_sig>'. Unsigned or tampered cookies are rejected and cart is reset.
Static asset cache headers — Add 'Cache-Control: public, max-age=86400' to CSS and asset responses in serve_asset().