Content Security Policy middleware
Content Security Policy helps prevent unwanted content being injected into your webpages; this can mitigate cross-site scripting (XSS) vulnerabilities, malicious frames, unwanted trackers, and more. If you want to learn how CSP works, check out the fantastic HTML5 Rocks guide, the Content Security Policy Reference, and the Content Security Policy specification. This module helps set Content Security Policies.
Usage:
const csp = require('helmet-csp')
app.use(csp({
directives: {
defaultSrc: ["'self'", 'default.com'],
scriptSrc: ["'self'", "'unsafe-inline'"],
styleSrc: ['style.com'],
fontSrc: ["'self'", 'fonts.com'],
imgSrc: ['img.com', 'data:'],
sandbox: ['allow-forms', 'allow-scripts'],
reportUri: '/report-violation',
objectSrc: ["'none'"],
upgradeInsecureRequests: true,
workerSrc: false
},
loose: false,
reportOnly: false,
setAllHeaders: false,
disableAndroid: false,
browserSniff: true
}))
There are a lot of inconsistencies in how browsers implement CSP. Helmet looks at the user-agent of the browser and sets the appropriate header and value for that browser. If no user-agent is matched, it will set all the headers with the 2.0 spec.
Supported directives
Directives can be kebab-cased (like script-src
) or camel-cased (like scriptSrc
); they are equivalent.
The following directives are supported:
base-uri
or baseUri
block-all-mixed-content
or blockAllMixedContent
child-src
or childSrc
connect-src
or connectSrc
default-src
or defaultSrc
font-src
or fontSrc
form-action
or formAction
frame-ancestors
or frameAncestors
frame-src
or frameSrc
img-src
or imgSrc
manifest-src
or manifestSrc
media-src
or mediaSrc
object-src
or objectSrc
plugin-types
or pluginTypes
prefetch-src
or prefetchSrc
report-to
or reportTo
report-uri
or reportUri
require-sri-for
or requireSriFor
sandbox
or sandbox
script-src
or scriptSrc
style-src
or styleSrc
upgrade-insecure-requests
or upgradeInsecureRequests
worker-src
or workerSrc
Handling CSP violations
If you've specified a reportUri
, browsers will POST any CSP violations to your server. Here's a simple example of a route that handles those reports:
app.use(bodyParser.json({
type: ['json', 'application/csp-report']
}))
app.post('/report-violation', (req, res) => {
if (req.body) {
console.log('CSP Violation: ', req.body)
} else {
console.log('CSP Violation: No data received!')
}
res.status(204).end()
})
Not all browsers send CSP violations in the same way, so this might require a little work.
Note: If you're using a CSRF module like csurf, you might have problems handling these violations without a valid CSRF token. The fix is to put your CSP report route above csurf middleware.
Generating nonces
You can dynamically generate nonces to allow inline <script>
tags to be safely evaluated. Here's a simple example:
const crypto = require('crypto')
app.use(function (req, res, next) {
res.locals.nonce = crypto.randomBytes(16).toString('hex')
next()
})
app.use(csp({
directives: {
scriptSrc: [
"'self'",
(req, res) => `'nonce-${res.locals.nonce}'`
]
}
}))
app.use((req, res) => {
res.end(`<script nonce="${res.locals.nonce}">alert(1 + 1);</script>`)
})
Using CSP with a CDN
The default behavior of CSP is generate headers tailored for the browser that's requesting your page. If you have a CDN in front of your application, the CDN may cache the wrong headers, rendering your CSP useless. Make sure to eschew a CDN when using this module or set the browserSniff
option to false
.
See also