Security
🔐 Security Headers
Section titled “🔐 Security Headers”Security headers are an important part of protecting your application from common attacks like cross-site scripting (XSS), clickjacking, and data injection. RedwoodSDK makes it easy to add these headers to your responses using middleware.
Here is an example of a middleware that adds a set of common security headers:
import type { RouteMiddleware } from "rwsdk/worker";
export const setCommonHeaders = (): RouteMiddleware => ({ response, rw: { nonce } }) => { const headers = response.headers; headers.set("X-Frame-Options", "DENY"); headers.set("X-Content-Type-Options", "nosniff"); headers.set("Referrer-Policy", "strict-origin-when-cross-origin"); headers.set( "Content-Security-Policy", `default-src 'self'; script-src 'self' 'nonce-${nonce}'; style-src 'self' 'unsafe-inline'; object-src 'none';` ); headers.set( "Permissions-Policy", "geolocation=(), microphone=(), camera=()" ); };
You can then apply this middleware in your src/worker.tsx
:
import { rwsdk } from "rwsdk/worker";import { setCommonHeaders } from "./app/headers.js";import { routes } from "./app/pages/routes.js";
export default { async fetch(request, env, ctx) { return rwsdk(request, env, ctx, { routes, middleware: [setCommonHeaders()], }); },};
Changing CSP (Content Security Policy) headers
Section titled “Changing CSP (Content Security Policy) headers”Sometimes you need to allow additional resources or modify the Content Security Policy (CSP) to accommodate third-party scripts, styles, or other assets. The CSP headers control what resources can be loaded and executed by your application.
Adding trusted domains
Section titled “Adding trusted domains”// In app/headers.tsheaders.set( "Content-Security-Policy", `default-src 'self'; script-src 'self' 'nonce-${nonce}'; style-src 'self' 'unsafe-inline'; object-src 'none';`, `default-src 'self'; script-src 'self' 'nonce-${nonce}' https://trusted-scripts.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' https://images.example.com; object-src 'none';`,);
Allowing images from multiple sources
Section titled “Allowing images from multiple sources”When working with images in your RedwoodSDK application, you may need to load images from different sources such as remote URLs or data URIs. The default CSP configuration doesn’t include an img-src
directive, which means images from external sources will be blocked.
To allow images from remote URLs and data URIs, add the img-src
directive to your CSP:
// In app/headers.tsheaders.set( "Content-Security-Policy", `default-src 'self'; script-src 'self' 'nonce-${nonce}'; style-src 'self' 'unsafe-inline'; object-src 'none';`, `default-src 'self'; script-src 'self' 'nonce-${nonce}'; style-src 'self' 'unsafe-inline'; img-src 'self' https://trusted-images.example.com data:; object-src 'none';`,);
This configuration allows:
'self'
- Images from your own domainhttps://trusted-images.example.com
- Images from specific trusted domainsdata:
- Data URIs (base64 encoded images)
Using nonce
for inline scripts
Section titled “Using nonce for inline scripts”Sometimes you need to include inline scripts in your application, but Content Security Policy (CSP) blocks them by default for security reasons. RedwoodSDK automatically generates a fresh, cryptographically secure nonce value for each request You can access this nonce in document or page components rendered by the router, using rw.nonce
.
export const Document = ({ rw, children }) => ( <html lang="en"> <head><!-- ... --></head> <body> <div id="root">{children}</div>
<!-- Set the nonce the inline script --> <script nonce={rw.nonce}>/* ... */</script> </body> </html>);
Lifting device permission restrictions
Section titled “Lifting device permission restrictions”Sometimes you need to allow your web application to access device features like the camera, microphone, or geolocation. These permissions are controlled by the Permissions-Policy
header.
To enable device access, you’ll need to modify the Permissions-Policy
header in your app/headers.ts
file:
// In app/headers.tsheaders.set( "Permissions-Policy", "geolocation=(), microphone=(), camera=()", "geolocation=self, microphone=self, camera=self");
The self
keyword allows the feature to be used only by your own domain.
For a complete reference, see the MDN Permissions Policy documentation.