diff options
author | Rigel Kent <par@rigelk.eu> | 2018-12-13 09:49:45 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2018-12-13 09:49:45 +0100 |
commit | 5e755fff9d70a7fd3c4f85bb524f1b774dd85b25 (patch) | |
tree | 699a0724de91f4151ec7d67b700f5b7736a78e45 | |
parent | 9ecac97be024cf2277872986950d7eec85cbc76e (diff) | |
download | PeerTube-5e755fff9d70a7fd3c4f85bb524f1b774dd85b25.tar.gz PeerTube-5e755fff9d70a7fd3c4f85bb524f1b774dd85b25.tar.zst PeerTube-5e755fff9d70a7fd3c4f85bb524f1b774dd85b25.zip |
add Content Security Policy (#1252)
* add Content Security Policy
* remove reflect-metadata on production builds to get rid of unsafe-eval
* fix baseCSP usage
* add SRI to CSP
* add blob: to media-src
* remove SRI
* CSP set to reportOnly
* adding data: to connect-src CSP
* remove block-all-mixed-content
* add report-uri support
-rw-r--r-- | client/src/environments/environment.ts | 7 | ||||
-rw-r--r-- | client/src/polyfills.ts | 8 | ||||
-rw-r--r-- | config/default.yaml | 2 | ||||
-rw-r--r-- | config/production.yaml.example | 2 | ||||
-rw-r--r-- | server.ts | 3 | ||||
-rw-r--r-- | server/controllers/client.ts | 3 | ||||
-rw-r--r-- | server/initializers/constants.ts | 1 | ||||
-rw-r--r-- | server/middlewares/csp.ts | 45 | ||||
-rw-r--r-- | server/middlewares/dnt.ts | 2 | ||||
-rw-r--r-- | server/middlewares/index.ts | 2 | ||||
-rw-r--r-- | support/docker/production/config/custom-environment-variables.yaml | 4 |
11 files changed, 75 insertions, 4 deletions
diff --git a/client/src/environments/environment.ts b/client/src/environments/environment.ts index 5bb6f4b34..1ea483554 100644 --- a/client/src/environments/environment.ts +++ b/client/src/environments/environment.ts | |||
@@ -2,6 +2,13 @@ | |||
2 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. | 2 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. |
3 | // The list of which env maps to which file can be found in `.angular-cli.json`. | 3 | // The list of which env maps to which file can be found in `.angular-cli.json`. |
4 | 4 | ||
5 | // Reflect.metadata polyfill is only needed in the JIT/dev mode. | ||
6 | // | ||
7 | // In order to load these polyfills early enough (before app code), polyfill.ts imports this file to | ||
8 | // to change the order in the final bundle. | ||
9 | import 'core-js/es6/reflect' | ||
10 | import 'core-js/es7/reflect' | ||
11 | |||
5 | export const environment = { | 12 | export const environment = { |
6 | production: false, | 13 | production: false, |
7 | hmr: false, | 14 | hmr: false, |
diff --git a/client/src/polyfills.ts b/client/src/polyfills.ts index 5dff18632..368908432 100644 --- a/client/src/polyfills.ts +++ b/client/src/polyfills.ts | |||
@@ -45,7 +45,13 @@ import 'core-js/es7/object' | |||
45 | /** IE10 and IE11 requires the following for the Reflect API. */ | 45 | /** IE10 and IE11 requires the following for the Reflect API. */ |
46 | 46 | ||
47 | // For Google Bot | 47 | // For Google Bot |
48 | import 'core-js/es6/reflect' | 48 | // import 'core-js/es6/reflect'; // --> dealt with in src/environment.ts |
49 | |||
50 | /** | ||
51 | * Evergreen browsers require these. | ||
52 | */ | ||
53 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. | ||
54 | // import 'core-js/es7/reflect' // --> dealt with in src/environment.ts | ||
49 | 55 | ||
50 | /** | 56 | /** |
51 | * Required to support Web Animations `@angular/platform-browser/animations`. | 57 | * Required to support Web Animations `@angular/platform-browser/animations`. |
diff --git a/config/default.yaml b/config/default.yaml index 080638a13..5fdb41250 100644 --- a/config/default.yaml +++ b/config/default.yaml | |||
@@ -163,6 +163,8 @@ instance: | |||
163 | "# If you would like to report a security issue\n# you may report it to:\nContact: https://github.com/Chocobozzz/PeerTube/blob/develop/SECURITY.md\nContact: mailto:" | 163 | "# If you would like to report a security issue\n# you may report it to:\nContact: https://github.com/Chocobozzz/PeerTube/blob/develop/SECURITY.md\nContact: mailto:" |
164 | 164 | ||
165 | services: | 165 | services: |
166 | # You can provide a reporting endpoint for Content Security Policy violations | ||
167 | csp-logger: | ||
166 | # Cards configuration to format video in Twitter | 168 | # Cards configuration to format video in Twitter |
167 | twitter: | 169 | twitter: |
168 | username: '@Chocobozzz' # Indicates the Twitter account for the website or platform on which the content was published | 170 | username: '@Chocobozzz' # Indicates the Twitter account for the website or platform on which the content was published |
diff --git a/config/production.yaml.example b/config/production.yaml.example index 770bb97da..c0dbf64b6 100644 --- a/config/production.yaml.example +++ b/config/production.yaml.example | |||
@@ -177,6 +177,8 @@ instance: | |||
177 | "# If you would like to report a security issue\n# you may report it to:\nContact: https://github.com/Chocobozzz/PeerTube/blob/develop/SECURITY.md\nContact: mailto:" | 177 | "# If you would like to report a security issue\n# you may report it to:\nContact: https://github.com/Chocobozzz/PeerTube/blob/develop/SECURITY.md\nContact: mailto:" |
178 | 178 | ||
179 | services: | 179 | services: |
180 | # You can provide a reporting endpoint for Content Security Policy violations | ||
181 | csp-logger: | ||
180 | # Cards configuration to format video in Twitter | 182 | # Cards configuration to format video in Twitter |
181 | twitter: | 183 | twitter: |
182 | username: '@Chocobozzz' # Indicates the Twitter account for the website or platform on which the content was published | 184 | username: '@Chocobozzz' # Indicates the Twitter account for the website or platform on which the content was published |
@@ -53,6 +53,9 @@ if (errorMessage !== null) { | |||
53 | app.set('trust proxy', CONFIG.TRUST_PROXY) | 53 | app.set('trust proxy', CONFIG.TRUST_PROXY) |
54 | 54 | ||
55 | // Security middleware | 55 | // Security middleware |
56 | import { baseCSP } from './server/middlewares' | ||
57 | |||
58 | app.use(baseCSP) | ||
56 | app.use(helmet({ | 59 | app.use(helmet({ |
57 | frameguard: { | 60 | frameguard: { |
58 | action: 'deny' // we only allow it for /videos/embed, see server/controllers/client.ts | 61 | action: 'deny' // we only allow it for /videos/embed, see server/controllers/client.ts |
diff --git a/server/controllers/client.ts b/server/controllers/client.ts index 73b40cf65..e5bd487f1 100644 --- a/server/controllers/client.ts +++ b/server/controllers/client.ts | |||
@@ -2,7 +2,7 @@ import * as express from 'express' | |||
2 | import { join } from 'path' | 2 | import { join } from 'path' |
3 | import { root } from '../helpers/core-utils' | 3 | import { root } from '../helpers/core-utils' |
4 | import { ACCEPT_HEADERS, STATIC_MAX_AGE } from '../initializers' | 4 | import { ACCEPT_HEADERS, STATIC_MAX_AGE } from '../initializers' |
5 | import { asyncMiddleware } from '../middlewares' | 5 | import { asyncMiddleware, embedCSP } from '../middlewares' |
6 | import { buildFileLocale, getCompleteLocale, is18nLocale, LOCALE_FILES } from '../../shared/models/i18n/i18n' | 6 | import { buildFileLocale, getCompleteLocale, is18nLocale, LOCALE_FILES } from '../../shared/models/i18n/i18n' |
7 | import { ClientHtml } from '../lib/client-html' | 7 | import { ClientHtml } from '../lib/client-html' |
8 | import { logger } from '../helpers/logger' | 8 | import { logger } from '../helpers/logger' |
@@ -22,6 +22,7 @@ clientsRouter.use('/videos/watch/:id', | |||
22 | 22 | ||
23 | clientsRouter.use('' + | 23 | clientsRouter.use('' + |
24 | '/videos/embed', | 24 | '/videos/embed', |
25 | embedCSP, | ||
25 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | 26 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
26 | res.removeHeader('X-Frame-Options') | 27 | res.removeHeader('X-Frame-Options') |
27 | res.sendFile(embedPath) | 28 | res.sendFile(embedPath) |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index ad61bee73..f1a734f48 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -290,6 +290,7 @@ const CONFIG = { | |||
290 | get SECURITYTXT_CONTACT () { return config.get<string>('admin.email') } | 290 | get SECURITYTXT_CONTACT () { return config.get<string>('admin.email') } |
291 | }, | 291 | }, |
292 | SERVICES: { | 292 | SERVICES: { |
293 | get 'CSP-LOGGER' () { return config.get<string>('services.csp-logger') }, | ||
293 | TWITTER: { | 294 | TWITTER: { |
294 | get USERNAME () { return config.get<string>('services.twitter.username') }, | 295 | get USERNAME () { return config.get<string>('services.twitter.username') }, |
295 | get WHITELISTED () { return config.get<boolean>('services.twitter.whitelisted') } | 296 | get WHITELISTED () { return config.get<boolean>('services.twitter.whitelisted') } |
diff --git a/server/middlewares/csp.ts b/server/middlewares/csp.ts new file mode 100644 index 000000000..a0ed3710b --- /dev/null +++ b/server/middlewares/csp.ts | |||
@@ -0,0 +1,45 @@ | |||
1 | import * as helmet from 'helmet' | ||
2 | import { CONFIG } from '../initializers/constants' | ||
3 | |||
4 | const baseDirectives = Object.assign({}, | ||
5 | { | ||
6 | defaultSrc: ["'none'"], // by default, not specifying default-src = '*' | ||
7 | connectSrc: ['*', 'data:'], | ||
8 | mediaSrc: ["'self'", 'https:', 'blob:'], | ||
9 | fontSrc: ["'self'", 'data:'], | ||
10 | imgSrc: ["'self'", 'data:'], | ||
11 | scriptSrc: ["'self' 'unsafe-inline'"], | ||
12 | styleSrc: ["'self' 'unsafe-inline'"], | ||
13 | // objectSrc: ["'none'"], // only define to allow plugins, else let defaultSrc 'none' block it | ||
14 | formAction: ["'self'"], | ||
15 | frameAncestors: ["'none'"], | ||
16 | baseUri: ["'self'"], | ||
17 | pluginTypes: ["'none'"], | ||
18 | manifestSrc: ["'self'"], | ||
19 | frameSrc: ["'self'"], // instead of deprecated child-src / self because of test-embed | ||
20 | workerSrc: ["'self'"], // instead of deprecated child-src | ||
21 | upgradeInsecureRequests: true | ||
22 | }, | ||
23 | (CONFIG.SERVICES['CSP-LOGGER'] != null) ? { reportUri: CONFIG.SERVICES['CSP-LOGGER'] } : {} | ||
24 | ) | ||
25 | |||
26 | const baseCSP = helmet.contentSecurityPolicy({ | ||
27 | directives: baseDirectives, | ||
28 | browserSniff: false, | ||
29 | reportOnly: true | ||
30 | }) | ||
31 | |||
32 | const embedCSP = helmet.contentSecurityPolicy({ | ||
33 | directives: Object.assign(baseDirectives, { | ||
34 | frameAncestors: ['*'] | ||
35 | }), | ||
36 | browserSniff: false, // assumes a modern browser, but allows CDN in front | ||
37 | reportOnly: true | ||
38 | }) | ||
39 | |||
40 | // --------------------------------------------------------------------------- | ||
41 | |||
42 | export { | ||
43 | baseCSP, | ||
44 | embedCSP | ||
45 | } | ||
diff --git a/server/middlewares/dnt.ts b/server/middlewares/dnt.ts index cabad39c6..607def855 100644 --- a/server/middlewares/dnt.ts +++ b/server/middlewares/dnt.ts | |||
@@ -10,4 +10,4 @@ const advertiseDoNotTrack = (_, res, next) => { | |||
10 | 10 | ||
11 | export { | 11 | export { |
12 | advertiseDoNotTrack | 12 | advertiseDoNotTrack |
13 | } | 13 | } |
diff --git a/server/middlewares/index.ts b/server/middlewares/index.ts index 0cef26953..b758a8586 100644 --- a/server/middlewares/index.ts +++ b/server/middlewares/index.ts | |||
@@ -6,3 +6,5 @@ export * from './pagination' | |||
6 | export * from './servers' | 6 | export * from './servers' |
7 | export * from './sort' | 7 | export * from './sort' |
8 | export * from './user-right' | 8 | export * from './user-right' |
9 | export * from './dnt' | ||
10 | export * from './csp' | ||
diff --git a/support/docker/production/config/custom-environment-variables.yaml b/support/docker/production/config/custom-environment-variables.yaml index cfc30632c..550f1ad80 100644 --- a/support/docker/production/config/custom-environment-variables.yaml +++ b/support/docker/production/config/custom-environment-variables.yaml | |||
@@ -101,9 +101,11 @@ transcoding: | |||
101 | 1080: | 101 | 1080: |
102 | __name: "PEERTUBE_TRANSCODING_1080P" | 102 | __name: "PEERTUBE_TRANSCODING_1080P" |
103 | __format: "json" | 103 | __format: "json" |
104 | |||
105 | 104 | ||
106 | instance: | 105 | instance: |
107 | name: "PEERTUBE_INSTANCE_NAME" | 106 | name: "PEERTUBE_INSTANCE_NAME" |
108 | description: "PEERTUBE_INSTANCE_DESCRIPTION" | 107 | description: "PEERTUBE_INSTANCE_DESCRIPTION" |
109 | terms: "PEERTUBE_INSTANCE_TERMS" | 108 | terms: "PEERTUBE_INSTANCE_TERMS" |
109 | |||
110 | services: | ||
111 | csp-logger: "PEERTUBE_SERVICES_CSPLOGGER" | ||