UNPKG

@appwarden/middleware

Version:

Instantly disable all user interaction with your app deployed on Cloudflare or Vercel

191 lines (135 loc) 5.44 kB
--- name: appwarden-middleware-csp description: > Configure nonce-based Content Security Policy for Appwarden on Cloudflare. Edit the domain configuration file, start in report-only mode, inject nonces into HTML, redeploy the universal middleware, and switch to enforced after validation. This skill is Cloudflare-only; Vercel does not support nonce-based CSP rewriting. metadata: type: core library: "@appwarden/middleware" library_version: "3.16.3" sources: - "appwarden/appwarden-core-b:websites/appwarden-io/docs/src/content/docs/docs/guides/managing-content-security-policy.mdx" - "appwarden/middleware:src/schemas/use-content-security-policy.ts" - "appwarden/middleware:src/schemas/cloudflare.ts" --- # Appwarden Middleware — Configure Nonce-Based CSP on Cloudflare Nonce-based CSP is supported on Cloudflare Workers and Cloudflare framework adapters that rewrite HTML. It is not supported on Vercel or on the Next.js Cloudflare (OpenNext) adapter because those platforms cannot inject nonces into HTML. ## Setup 1. Locate your domain configuration file in the domain configuration repository, typically `.appwarden/domains/your-app.yml`. 2. Add a `csp-mode` and `csp-directives` block. 3. Open a pull request, merge it, and redeploy: - For the universal Cloudflare middleware: redeploy via `deploy-appwarden.yml`. - For Cloudflare framework adapters: redeploy the website itself so the updated middleware runs in the new build. ## Core Patterns ### Domain configuration file ```yaml # .appwarden/domains/your-app.yml domain: your-app.example.com csp-mode: report-only csp-directives: default-src: - "'self'" script-src: - "'self'" - "{{nonce}}" style-src: - "'self'" - "{{nonce}}" object-src: - "'none'" ``` Valid `csp-mode` values are `report-only`, `disabled`, or `enforced`. ### Roll out from report-only to enforced Start with `csp-mode: report-only` to collect violations without blocking anything. After the browser console shows no violations, change to `csp-mode: enforced` and redeploy. ### Inject nonces into HTML The Cloudflare middleware rewrites the HTML response and replaces `{{nonce}}` with a per-request nonce. Add `nonce` attributes to `<script>` and `<style>` tags: ```html <script nonce="{{nonce}}" src="/app.js"></script> <link rel="stylesheet" nonce="{{nonce}}" href="/styles.css" /> ``` ### Verify with browser DevTools After deploying: 1. Open DevTools > Network. 2. Select a document request. 3. Check the response headers for `Content-Security-Policy` (or `Content-Security-Policy-Report-Only` in report-only mode). 4. View the page source and confirm `nonce` attributes are present. ## Common Mistakes ### CRITICAL Using {{nonce}} on a platform that does not support HTML rewriting Wrong: ```yaml # Vercel Edge Middleware config csp-mode: enforced csp-directives: script-src: - "'self'" - "{{nonce}}" ``` Correct: ```yaml # Use headers-only CSP on Vercel; use {{nonce}} only on Cloudflare Workers / adapters csp-mode: enforced csp-directives: default-src: - "'self'" ``` Nonce placeholders are only rewritten on Cloudflare platforms that rewrite HTML. Vercel and the Next.js Cloudflare (OpenNext) adapter leave the placeholder in the header. ### CRITICAL Trying to configure nonce-based CSP on Vercel Wrong: ```typescript // middleware.ts on Vercel contentSecurityPolicy: { mode: 'enforced', directives: { 'script-src': ["'self'", '{{nonce}}"] }, } ``` Correct: ```typescript // Vercel: headers-only CSP, or move to Cloudflare for nonce support contentSecurityPolicy: { mode: 'enforced', directives: { 'default-src': ["'self'"] }, } ``` Vercel Edge Middleware cannot rewrite HTML to inject nonces. ### MEDIUM Starting CSP in enforced mode before validating directives Wrong: ```yaml csp-mode: enforced ``` Correct: ```yaml csp-mode: report-only ``` Start in report-only mode to collect violations. Switch to enforced only after no violations are reported. ### MEDIUM Passing CSP_DIRECTIVES as a malformed JSON string Wrong: ```bash CSP_DIRECTIVES="{ 'script-src': ['self'] }" ``` Correct: ```bash CSP_DIRECTIVES='{"script-src": ["'\''self'\''"]}' ``` The schema parses string directives with `JSON.parse`. Malformed JSON causes a validation error surfaced in the heartbeat response. ### MEDIUM Editing CSP only in middleware code without updating the domain configuration Wrong: ```typescript // Only editing CSP in the worker code, ignoring .appwarden/domains/your-app.yml ``` Correct: ```yaml # Update .appwarden/domains/your-app.yml, merge, and redeploy via deploy-appwarden.yml ``` For the universal Cloudflare middleware, CSP is sourced from the domain configuration file. Code-level overrides only apply to framework adapters. ### MEDIUM Not redeploying the universal middleware after merging CSP changes Wrong: ```text // Merge the PR and expect CSP to apply immediately ``` Correct: ```text // Merge the PR, then trigger deploy-appwarden.yml ``` Changes to the domain configuration file only take effect after the deploy workflow runs and deploys the updated Worker. For framework adapters, the website itself must also be redeployed because the middleware is bundled into the application build. ## Next Steps - For framework-specific CSP behavior, see `appwarden-middleware-cloudflare-adapters`. - For Vercel headers-only CSP, see `appwarden-middleware-vercel-edge`.