Node.js CSP Integration
Add CSP headers to Express, Koa, Fastify, or any Node.js HTTP server.
Prerequisites
Section titled “Prerequisites”- Node.js 18+
- An HTTP framework (Express, Koa, Fastify, etc.)
Quick Start with Express
Section titled “Quick Start with Express”const express = require("express");const app = express();
// CSP Middlewareapp.use((req, res, next) => { res.setHeader( "Content-Security-Policy-Report-Only", "default-src 'self'; report-uri https://ingest.headerhawk.com/csp/YOUR_SITE_ID" ); next();});
app.listen(3000);Using Helmet (Recommended)
Section titled “Using Helmet (Recommended)”Helmet provides a cleaner API:
npm install helmetconst express = require("express");const helmet = require("helmet");
const app = express();
app.use( helmet.contentSecurityPolicy({ directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'"], styleSrc: ["'self'", "'unsafe-inline'"], imgSrc: ["'self'", "data:", "https:"], reportUri: ["https://ingest.headerhawk.com/csp/YOUR_SITE_ID"], }, reportOnly: true, // Remove this line to enforce }));
app.listen(3000);Fastify
Section titled “Fastify”const fastify = require("fastify")();
fastify.addHook("onSend", (request, reply, payload, done) => { reply.header( "Content-Security-Policy-Report-Only", "default-src 'self'; report-uri https://ingest.headerhawk.com/csp/YOUR_SITE_ID" ); done();});
fastify.listen({ port: 3000 });const Koa = require("koa");const app = new Koa();
app.use(async (ctx, next) => { ctx.set( "Content-Security-Policy-Report-Only", "default-src 'self'; report-uri https://ingest.headerhawk.com/csp/YOUR_SITE_ID" ); await next();});
app.listen(3000);Dynamic Policies with Nonces
Section titled “Dynamic Policies with Nonces”Generate policies based on request context:
const crypto = require("crypto");
app.use((req, res, next) => { const nonce = crypto.randomBytes(16).toString("base64"); res.locals.nonce = nonce;
res.setHeader( "Content-Security-Policy-Report-Only", `default-src 'self'; script-src 'self' 'nonce-${nonce}'; report-uri https://ingest.headerhawk.com/csp/YOUR_SITE_ID` ); next();});Then in your templates:
<script nonce="<%= nonce %>"> // Your inline script</script>TypeScript Example
Section titled “TypeScript Example”import express, { Request, Response, NextFunction } from "express";
const app = express();
const cspMiddleware = (req: Request, res: Response, next: NextFunction) => { const policy = [ "default-src 'self'", "script-src 'self'", "style-src 'self' 'unsafe-inline'", "img-src 'self' data: https:", "report-uri https://ingest.headerhawk.com/csp/YOUR_SITE_ID", ].join("; ");
res.setHeader("Content-Security-Policy-Report-Only", policy); next();};
app.use(cspMiddleware);app.listen(3000);Troubleshooting
Section titled “Troubleshooting”Reports Not Appearing
Section titled “Reports Not Appearing”- Check the header is being set:
curl -I http://localhost:3000 - Verify the site ID is correct
- Check for typos in the report-uri
CORS Issues with Report-URI
Section titled “CORS Issues with Report-URI”The Header Hawk ingestion endpoint handles CORS automatically. If you see CORS errors, verify you’re using the correct endpoint URL.
Next Steps
Section titled “Next Steps”- CSP Directive Reference
- Next.js Integration (if using Next.js)