This commit is contained in:
Tutur33
2023-11-24 22:35:41 +01:00
parent 3c0b507a93
commit 7644b2a0f7
45165 changed files with 4803356 additions and 3 deletions
+122
View File
@@ -0,0 +1,122 @@
# Changelog
## 3.4.0 - 2021-05-02
### Added
- New `useDefaults` option, defaulting to `false`, lets you selectively override defaults more easily
## 3.3.1 - 2020-12-27
### Fixed
- Broken TypeScript types. See [#283](https://github.com/helmetjs/helmet/issues/283)
## 3.3.0 - 2020-12-27
### Added
- Setting the `default-src` to `contentSecurityPolicy.dangerouslyDisableDefaultSrc` disables it
## 3.2.0 - 2020-11-01
### Added
- Get the default directives with `contentSecurityPolicy.getDefaultDirectives()`
## 3.1.0 - 2020-08-15
### Added
- Directive values can now include functions, as they could in Helmet 3. See [#243](https://github.com/helmetjs/helmet/issues/243)
## 3.0.0 - 2020-08-02
### Added
- If no `default-src` directive is supplied, an error is thrown
- Directive lists can be any iterable, not just arrays
### Changed
- There is now a default set of directives if none are supplied
- Duplicate keys now throw an error. See [helmetjs/csp#73](https://github.com/helmetjs/csp/issues/73)
- This middleware is more lenient, allowing more directive names or values
### Removed
- Removed browser sniffing (including the `browserSniff` parameter). See [#97](https://github.com/helmetjs/csp/issues/97)
- Removed conditional support. This includes directive functions and support for a function as the `reportOnly`. [Read this if you need help.](https://github.com/helmetjs/helmet/wiki/Conditionally-using-middleware)
- Removed a lot of checks—you should be checking your CSP with a different tool
- Removed support for legacy headers (and therefore the `setAllHeaders` parameter). [Read this if you need help.](https://github.com/helmetjs/helmet/wiki/Setting-legacy-Content-Security-Policy-headers-in-Helmet-4)
- Dropped support for old Node versions. Node 10+ is now required
- Removed the `loose` option
- Removed support for functions as directive values. You must supply an iterable of strings
- Removed the `disableAndroid` option
## 2.9.5 - 2020-02-22
### Changed
- Updated `bowser` subdependency from 2.7.0 to 2.9.0
### Fixed
- Fixed an issue some people were having when importing the `bowser` subdependency. See [#96](https://github.com/helmetjs/csp/issues/96) and [#101](https://github.com/helmetjs/csp/pull/101)
- Fixed a link in the readme. See [#100](https://github.com/helmetjs/csp/pull/100)
## 2.9.4 - 2019-10-21
### Changed
- Updated `bowser` subdependency from 2.6.1 to 2.7.0. See [#94](https://github.com/helmetjs/csp/pull/94)
## 2.9.3 - 2019-09-30
### Fixed
- Published a missing TypeScript type definition file. See [#90](https://github.com/helmetjs/csp/issues/90)
## 2.9.2 - 2019-09-20
### Fixed
- Fixed a bug where a request from Firefox 4 could delete `default-src` from future responses
- Fixed tablet PC detection by updating `bowser` subdependency to latest version
## 2.9.1 - 2019-09-04
### Changed
- Updated `bowser` subdependency from 2.5.3 to 2.5.4. See [#88](https://github.com/helmetjs/csp/pull/88)
### Fixed
- The "security" keyword was declared twice in package metadata. See [#87](https://github.com/helmetjs/csp/pull/87)
## 2.9.0 - 2019-08-28
### Added
- Added TypeScript type definitions. See [#86](https://github.com/helmetjs/csp/pull/86)
### Fixed
- Switched from `platform` to `bowser` to quiet a security vulnerability warning. See [#80](https://github.com/helmetjs/csp/issues/80)
## 2.8.0 - 2019-07-24
### Added
- Added a new `sandbox` directive, `allow-downloads-without-user-activation` (see [#85](https://github.com/helmetjs/csp/pull/85))
- Created a changelog
- Added some package metadata
### Changed
- Updated documentation to use ES2015
- Updated documentation to remove dependency on UUID package
- Updated `content-security-policy-builder` to 2.1.0
- Excluded some files from the npm package
Changes in versions 2.7.1 and below can be found in [Helmet's changelog](https://github.com/helmetjs/helmet/blob/master/CHANGELOG.md).
+22
View File
@@ -0,0 +1,22 @@
The MIT License
Copyright (c) 2012-2021 Evan Hahn, Adam Baldwin
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+83
View File
@@ -0,0 +1,83 @@
# 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.
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 middleware helps set Content Security Policies.
Basic usage:
```javascript
const contentSecurityPolicy = require("helmet-csp");
app.use(
contentSecurityPolicy({
useDefaults: true,
directives: {
defaultSrc: ["'self'", "default.example"],
scriptSrc: ["'self'", "js.example.com"],
objectSrc: ["'none'"],
upgradeInsecureRequests: [],
},
reportOnly: false,
})
);
```
If no directives are supplied, the following policy is set (whitespace added for readability):
default-src 'self';
base-uri 'self';
block-all-mixed-content;
font-src 'self' https: data:;
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 `false` by default, but will be `true` in the next major version of this module.
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.
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");
app.use((req, res, next) => {
res.locals.nonce = crypto.randomBytes(16).toString("hex");
next();
});
app.use((req, res, next) => {
csp({
useDefaults: true,
directives: {
scriptSrc: ["'self'", `'nonce-${res.locals.nonce}'`],
},
})(req, res, next);
});
app.use((req, res) => {
res.end(`<script nonce="${res.locals.nonce}">alert(1 + 1);</script>`);
});
```
## See also
- [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/)
+23
View File
@@ -0,0 +1,23 @@
/// <reference types="node" />
import { IncomingMessage, ServerResponse } from "http"
interface ContentSecurityPolicyDirectiveValueFunction {
(req: IncomingMessage, res: ServerResponse): string
}
declare type ContentSecurityPolicyDirectiveValue = string | ContentSecurityPolicyDirectiveValueFunction
export interface ContentSecurityPolicyOptions {
useDefaults?: boolean
directives?: Record<string, null | Iterable<ContentSecurityPolicyDirectiveValue> | typeof dangerouslyDisableDefaultSrc>
reportOnly?: boolean
}
interface ContentSecurityPolicy {
(options?: Readonly<ContentSecurityPolicyOptions>): (req: IncomingMessage, res: ServerResponse, next: (err?: Error) => void) => void
getDefaultDirectives: typeof getDefaultDirectives
dangerouslyDisableDefaultSrc: typeof dangerouslyDisableDefaultSrc
}
declare const dangerouslyDisableDefaultSrc: unique symbol
declare const getDefaultDirectives: () => {
[x: string]: Iterable<ContentSecurityPolicyDirectiveValue>
}
declare const contentSecurityPolicy: ContentSecurityPolicy
export default contentSecurityPolicy
export { getDefaultDirectives, dangerouslyDisableDefaultSrc }
+131
View File
@@ -0,0 +1,131 @@
"use strict"
Object.defineProperty(exports, "__esModule", { value: true })
exports.dangerouslyDisableDefaultSrc = exports.getDefaultDirectives = void 0
const dangerouslyDisableDefaultSrc = Symbol("dangerouslyDisableDefaultSrc")
exports.dangerouslyDisableDefaultSrc = dangerouslyDisableDefaultSrc
const DEFAULT_DIRECTIVES = {
"default-src": ["'self'"],
"base-uri": ["'self'"],
"block-all-mixed-content": [],
"font-src": ["'self'", "https:", "data:"],
"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": []
}
const getDefaultDirectives = () => Object.assign({}, DEFAULT_DIRECTIVES)
exports.getDefaultDirectives = getDefaultDirectives
const dashify = str => str.replace(/[A-Z]/g, capitalLetter => "-" + capitalLetter.toLowerCase())
const isDirectiveValueInvalid = directiveValue => /;|,/.test(directiveValue)
const has = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key)
function normalizeDirectives(options) {
const defaultDirectives = getDefaultDirectives()
const { useDefaults = false, directives: rawDirectives = defaultDirectives } = options
const result = new Map()
const directiveNamesSeen = new Set()
const directivesExplicitlyDisabled = new Set()
for (const rawDirectiveName in rawDirectives) {
if (!has(rawDirectives, rawDirectiveName)) {
continue
}
if (rawDirectiveName.length === 0 || /[^a-zA-Z0-9-]/.test(rawDirectiveName)) {
throw new Error(`Content-Security-Policy received an invalid directive name ${JSON.stringify(rawDirectiveName)}`)
}
const directiveName = dashify(rawDirectiveName)
if (directiveNamesSeen.has(directiveName)) {
throw new Error(`Content-Security-Policy received a duplicate directive ${JSON.stringify(directiveName)}`)
}
directiveNamesSeen.add(directiveName)
const rawDirectiveValue = rawDirectives[rawDirectiveName]
let directiveValue
if (rawDirectiveValue === null) {
if (directiveName === "default-src") {
throw new Error("Content-Security-Policy needs a default-src but it was set to `null`. If you really want to disable it, set it to `contentSecurityPolicy.dangerouslyDisableDefaultSrc`.")
}
directivesExplicitlyDisabled.add(directiveName)
continue
} else if (typeof rawDirectiveValue === "string") {
directiveValue = [rawDirectiveValue]
} else if (!rawDirectiveValue) {
throw new Error(`Content-Security-Policy received an invalid directive value for ${JSON.stringify(directiveName)}`)
} else if (rawDirectiveValue === dangerouslyDisableDefaultSrc) {
if (directiveName === "default-src") {
directivesExplicitlyDisabled.add("default-src")
continue
} else {
throw new Error(`Content-Security-Policy: tried to disable ${JSON.stringify(directiveName)} as if it were default-src; simply omit the key`)
}
} else {
directiveValue = rawDirectiveValue
}
for (const element of directiveValue) {
if (typeof element === "string" && isDirectiveValueInvalid(element)) {
throw new Error(`Content-Security-Policy received an invalid directive value for ${JSON.stringify(directiveName)}`)
}
}
result.set(directiveName, directiveValue)
}
if (useDefaults) {
Object.entries(defaultDirectives).forEach(([defaultDirectiveName, defaultDirectiveValue]) => {
if (!result.has(defaultDirectiveName) && !directivesExplicitlyDisabled.has(defaultDirectiveName)) {
result.set(defaultDirectiveName, defaultDirectiveValue)
}
})
}
if (!result.size) {
throw new Error("Content-Security-Policy has no directives. Either set some or disable the header")
}
if (!result.has("default-src") && !directivesExplicitlyDisabled.has("default-src")) {
throw new Error("Content-Security-Policy needs a default-src but none was provided. If you really want to disable it, set it to `contentSecurityPolicy.dangerouslyDisableDefaultSrc`.")
}
return result
}
function getHeaderValue(req, res, normalizedDirectives) {
let err
const result = []
normalizedDirectives.forEach((rawDirectiveValue, directiveName) => {
let directiveValue = ""
for (const element of rawDirectiveValue) {
directiveValue += " " + (element instanceof Function ? element(req, res) : element)
}
if (!directiveValue) {
result.push(directiveName)
} else if (isDirectiveValueInvalid(directiveValue)) {
err = new Error(`Content-Security-Policy received an invalid directive value for ${JSON.stringify(directiveName)}`)
} else {
result.push(`${directiveName}${directiveValue}`)
}
})
return err ? err : result.join(";")
}
const contentSecurityPolicy = function contentSecurityPolicy(options = {}) {
if ("loose" in options) {
console.warn("Content-Security-Policy middleware no longer needs the `loose` parameter. You should remove it.")
}
if ("setAllHeaders" in options) {
console.warn("Content-Security-Policy middleware no longer supports the `setAllHeaders` parameter. See <https://github.com/helmetjs/helmet/wiki/Setting-legacy-Content-Security-Policy-headers-in-Helmet-4>.")
}
;["disableAndroid", "browserSniff"].forEach(deprecatedOption => {
if (deprecatedOption in options) {
console.warn(`Content-Security-Policy middleware no longer does browser sniffing, so you can remove the \`${deprecatedOption}\` option. See <https://github.com/helmetjs/csp/issues/97> for discussion.`)
}
})
const headerName = options.reportOnly ? "Content-Security-Policy-Report-Only" : "Content-Security-Policy"
const normalizedDirectives = normalizeDirectives(options)
return function contentSecurityPolicyMiddleware(req, res, next) {
const result = getHeaderValue(req, res, normalizedDirectives)
if (result instanceof Error) {
next(result)
} else {
res.setHeader(headerName, result)
next()
}
}
}
contentSecurityPolicy.getDefaultDirectives = getDefaultDirectives
contentSecurityPolicy.dangerouslyDisableDefaultSrc = dangerouslyDisableDefaultSrc
module.exports = contentSecurityPolicy
exports.default = contentSecurityPolicy
+1
View File
@@ -0,0 +1 @@
{"author":"Adam Baldwin <adam@npmjs.com> (https://evilpacket.net)","contributors":["Evan Hahn <me@evanhahn.com> (https://evanhahn.com)","Ryan Cannon <ryan@ryancannon.com> (https://ryancannon.com)"],"license":"MIT","homepage":"https://helmetjs.github.io/","bugs":{"url":"https://github.com/helmetjs/helmet/issues","email":"me@evanhahn.com"},"repository":{"type":"git","url":"git://github.com/helmetjs/helmet.git"},"engines":{"node":">=10.0.0"},"files":["CHANGELOG.md","LICENSE","README.md","index.js","index.d.ts"],"main":"index.js","typings":"index.d.ts","name":"helmet-csp","description":"Content Security Policy middleware","version":"3.4.0","keywords":["express","security","content-security-policy","csp","xss"]}