-
Notifications
You must be signed in to change notification settings - Fork 368
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
71 additions
and
79 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,84 +1,92 @@ | ||
# Content Security Policy middleware | ||
|
||
Content Security Policy (CSP) helps prevent unwanted content from being injected/loaded into your webpages. This can mitigate cross-site scripting (XSS) vulnerabilities, clickjacking, formjacking, malicious frames, unwanted trackers, and other web client-side attacks. | ||
The `Content-Security-Policy` header mitigates a large number of attacks, such as [cross-site scripting][XSS]. See [MDN's introductory article on Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP). | ||
|
||
If you want to learn how CSP works, check out the fantastic [HTML5 Rocks guide](https://www.html5rocks.com/en/tutorials/security/content-security-policy/), the [Content Security Policy Reference](https://content-security-policy.com/), and the [Content Security Policy specification](https://www.w3.org/TR/CSP/). | ||
This header is powerful but likely requires some configuration for your specific app. | ||
|
||
This middleware helps set Content Security Policies. | ||
|
||
Basic usage: | ||
To configure this header, pass an object with a nested `directives` object. Each key is a directive name in camel case (such as `defaultSrc`) or kebab case (such as `default-src`). Each value is an array (or other iterable) of strings or functions for that directive. If a function appears in the array, it will be called with the request and response objects. | ||
|
||
```javascript | ||
const contentSecurityPolicy = require("helmet-csp"); | ||
|
||
// Sets all of the defaults, but overrides `script-src` | ||
// and disables the default `style-src`. | ||
app.use( | ||
contentSecurityPolicy({ | ||
useDefaults: true, | ||
directives: { | ||
defaultSrc: ["'self'", "default.example"], | ||
scriptSrc: ["'self'", "js.example.com"], | ||
objectSrc: ["'none'"], | ||
upgradeInsecureRequests: [], | ||
"script-src": ["'self'", "example.com"], | ||
"style-src": null, | ||
}, | ||
reportOnly: false, | ||
}), | ||
); | ||
``` | ||
|
||
If no directives are supplied, the following policy is set (whitespace added for readability): | ||
|
||
default-src 'self'; | ||
base-uri 'self'; | ||
font-src 'self' https: data:; | ||
form-action 'self'; | ||
frame-ancestors 'self'; | ||
img-src 'self' data:; | ||
object-src 'none'; | ||
script-src 'self'; | ||
script-src-attr 'none'; | ||
style-src 'self' https: 'unsafe-inline'; | ||
upgrade-insecure-requests | ||
|
||
You can use this default with the `useDefaults` option. `useDefaults` is `true` by default. | ||
|
||
You can also get the default directives object with `contentSecurityPolicy.getDefaultDirectives()`. | ||
|
||
You can set any directives you wish. `defaultSrc` is required, but can be explicitly disabled by setting its value to `contentSecurityPolicy.dangerouslyDisableDefaultSrc`. Directives can be kebab-cased (like `script-src`) or camel-cased (like `scriptSrc`). They are equivalent, but duplicates are not allowed. | ||
|
||
The `reportOnly` option, if set to `true`, sets the `Content-Security-Policy-Report-Only` header instead. If you want to set _both_ the normal and `Report-Only` headers, see [this code snippet](https://github.com/helmetjs/helmet/issues/351#issuecomment-1015498560). | ||
|
||
This middleware does minimal validation. You should use a more sophisticated CSP validator, like [Google's CSP Evaluator](https://csp-evaluator.withgoogle.com/), to make sure your CSP looks good. | ||
|
||
## Recipe: generating nonces | ||
|
||
You can dynamically generate nonces to allow inline `<script>` tags to be safely evaluated. Here's a simple example: | ||
|
||
```js | ||
const crypto = require("crypto"); | ||
const contentSecurityPolicy = require("helmet-csp"); | ||
|
||
// Sets the `script-src` directive to | ||
// "'self' 'nonce-e33cc...'" | ||
// (or similar) | ||
app.use((req, res, next) => { | ||
res.locals.nonce = crypto.randomBytes(32).toString("hex"); | ||
res.locals.cspNonce = crypto.randomBytes(32).toString("hex"); | ||
next(); | ||
}); | ||
app.use( | ||
contentSecurityPolicy({ | ||
directives: { | ||
scriptSrc: ["'self'", (req, res) => `'nonce-${res.locals.cspNonce}'`], | ||
}, | ||
}), | ||
); | ||
``` | ||
|
||
app.use((req, res, next) => { | ||
These directives are merged into a default policy, which you can disable by setting `useDefaults` to `false`. | ||
|
||
```javascript | ||
// Sets "Content-Security-Policy: default-src 'self'; | ||
// script-src 'self' example.com;object-src 'none'; | ||
// upgrade-insecure-requests" | ||
app.use( | ||
contentSecurityPolicy({ | ||
useDefaults: true, | ||
useDefaults: false, | ||
directives: { | ||
scriptSrc: ["'self'", `'nonce-${res.locals.nonce}'`], | ||
defaultSrc: ["'self'"], | ||
scriptSrc: ["'self'", "example.com"], | ||
objectSrc: ["'none'"], | ||
upgradeInsecureRequests: [], | ||
}, | ||
})(req, res, next); | ||
}); | ||
}), | ||
); | ||
``` | ||
|
||
You can get the default directives object with `contentSecurityPolicy.getDefaultDirectives()`. Here is the default policy (formatted for readability): | ||
|
||
app.use((req, res) => { | ||
res.end(`<script nonce="${res.locals.nonce}">alert(1 + 1);</script>`); | ||
}); | ||
``` | ||
default-src 'self'; | ||
base-uri 'self'; | ||
font-src 'self' https: data:; | ||
form-action 'self'; | ||
frame-ancestors 'self'; | ||
img-src 'self' data:; | ||
object-src 'none'; | ||
script-src 'self'; | ||
script-src-attr 'none'; | ||
style-src 'self' https: 'unsafe-inline'; | ||
upgrade-insecure-requests | ||
``` | ||
|
||
The `default-src` directive can be explicitly disabled by setting its value to `contentSecurityPolicy.dangerouslyDisableDefaultSrc`, but this is not recommended. | ||
|
||
You can set the [`Content-Security-Policy-Report-Only`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only) instead: | ||
|
||
## See also | ||
```javascript | ||
// Sets the Content-Security-Policy-Report-Only header | ||
app.use( | ||
contentSecurityPolicy({ | ||
directives: { | ||
/* ... */ | ||
}, | ||
reportOnly: true, | ||
}), | ||
); | ||
``` | ||
|
||
- [Google's CSP Evaluator tool](https://csp-evaluator.withgoogle.com/) | ||
- [CSP Scanner](https://cspscanner.com/) | ||
- [GitHub's CSP journey](https://githubengineering.com/githubs-csp-journey/) | ||
- [Content Security Policy for Single Page Web Apps](https://developer.squareup.com/blog/content-security-policy-for-single-page-web-apps/) | ||
This module performs very little validation on your CSP. You should rely on CSP checkers like [CSP Evaluator](https://csp-evaluator.withgoogle.com/) instead. |