Skip to content

Security

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:

src/app/headers.ts
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:

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.

// In app/headers.ts
headers.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';`,
);

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.ts
headers.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 domain
  • https://trusted-images.example.com - Images from specific trusted domains
  • data: - Data URIs (base64 encoded images)

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>
);

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.ts
headers.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.