]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
add Content Security Policy (#1252)
authorRigel Kent <par@rigelk.eu>
Thu, 13 Dec 2018 08:49:45 +0000 (09:49 +0100)
committerChocobozzz <me@florianbigard.com>
Thu, 13 Dec 2018 08:49:45 +0000 (09:49 +0100)
* 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

client/src/environments/environment.ts
client/src/polyfills.ts
config/default.yaml
config/production.yaml.example
server.ts
server/controllers/client.ts
server/initializers/constants.ts
server/middlewares/csp.ts [new file with mode: 0644]
server/middlewares/dnt.ts
server/middlewares/index.ts
support/docker/production/config/custom-environment-variables.yaml

index 5bb6f4b3446fecce885eb6187219f5e7e7aa9ea2..1ea4835548ed0c41eaeb759d9c871f19298ef0bf 100644 (file)
@@ -2,6 +2,13 @@
 // `ng build --env=prod` then `environment.prod.ts` will be used instead.
 // The list of which env maps to which file can be found in `.angular-cli.json`.
 
+// Reflect.metadata polyfill is only needed in the JIT/dev mode.
+//
+// In order to load these polyfills early enough (before app code), polyfill.ts imports this file to
+// to change the order in the final bundle.
+import 'core-js/es6/reflect'
+import 'core-js/es7/reflect'
+
 export const environment = {
   production: false,
   hmr: false,
index 5dff18632b0f4df145c13bbea325ea60227de0b7..3689084324c021070ed6a08241f68e581104fdd6 100644 (file)
@@ -45,7 +45,13 @@ import 'core-js/es7/object'
 /** IE10 and IE11 requires the following for the Reflect API. */
 
 // For Google Bot
-import 'core-js/es6/reflect'
+// import 'core-js/es6/reflect'; // --> dealt with in src/environment.ts
+
+/**
+ * Evergreen browsers require these.
+ */
+// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
+// import 'core-js/es7/reflect' // --> dealt with in src/environment.ts
 
 /**
  * Required to support Web Animations `@angular/platform-browser/animations`.
index 080638a133160407481ddba64afc2e2ff48deebe..5fdb41250fd90683957241b294bfcf626fbe48d1 100644 (file)
@@ -163,6 +163,8 @@ instance:
     "# 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:"
 
 services:
+  # You can provide a reporting endpoint for Content Security Policy violations
+  csp-logger:
   # Cards configuration to format video in Twitter
   twitter:
     username: '@Chocobozzz' # Indicates the Twitter account for the website or platform on which the content was published
index 770bb97da7a499174014e25fde1b05d414542a9a..c0dbf64b61eb748c4466997f11ca87c57c604577 100644 (file)
@@ -177,6 +177,8 @@ instance:
     "# 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:"
 
 services:
+  # You can provide a reporting endpoint for Content Security Policy violations
+  csp-logger:
   # Cards configuration to format video in Twitter
   twitter:
     username: '@Chocobozzz' # Indicates the Twitter account for the website or platform on which the content was published
index 4a2a6ddf554532ca757a5dc463331fa022e7058f..6dff16f46214eb33eec2b4b485ea68ff1d942c92 100644 (file)
--- a/server.ts
+++ b/server.ts
@@ -53,6 +53,9 @@ if (errorMessage !== null) {
 app.set('trust proxy', CONFIG.TRUST_PROXY)
 
 // Security middleware
+import { baseCSP } from './server/middlewares'
+
+app.use(baseCSP)
 app.use(helmet({
   frameguard: {
     action: 'deny' // we only allow it for /videos/embed, see server/controllers/client.ts
index 73b40cf6513c3941fe5fe9ef1b76c9691db0a456..e5bd487f1475fd412962d9f39e3859b3b4c98c6a 100644 (file)
@@ -2,7 +2,7 @@ import * as express from 'express'
 import { join } from 'path'
 import { root } from '../helpers/core-utils'
 import { ACCEPT_HEADERS, STATIC_MAX_AGE } from '../initializers'
-import { asyncMiddleware } from '../middlewares'
+import { asyncMiddleware, embedCSP } from '../middlewares'
 import { buildFileLocale, getCompleteLocale, is18nLocale, LOCALE_FILES } from '../../shared/models/i18n/i18n'
 import { ClientHtml } from '../lib/client-html'
 import { logger } from '../helpers/logger'
@@ -22,6 +22,7 @@ clientsRouter.use('/videos/watch/:id',
 
 clientsRouter.use('' +
   '/videos/embed',
+  embedCSP,
   (req: express.Request, res: express.Response, next: express.NextFunction) => {
     res.removeHeader('X-Frame-Options')
     res.sendFile(embedPath)
index ad61bee738633a16bcf028091cd4e1adf5fcdaff..f1a734f48c176794e41ebe771d704fe39e728246 100644 (file)
@@ -290,6 +290,7 @@ const CONFIG = {
     get SECURITYTXT_CONTACT () { return config.get<string>('admin.email') }
   },
   SERVICES: {
+    get 'CSP-LOGGER' () { return config.get<string>('services.csp-logger') },
     TWITTER: {
       get USERNAME () { return config.get<string>('services.twitter.username') },
       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 (file)
index 0000000..a0ed371
--- /dev/null
@@ -0,0 +1,45 @@
+import * as helmet from 'helmet'
+import { CONFIG } from '../initializers/constants'
+
+const baseDirectives = Object.assign({},
+  {
+    defaultSrc: ["'none'"], // by default, not specifying default-src = '*'
+    connectSrc: ['*', 'data:'],
+    mediaSrc: ["'self'", 'https:', 'blob:'],
+    fontSrc: ["'self'", 'data:'],
+    imgSrc: ["'self'", 'data:'],
+    scriptSrc: ["'self' 'unsafe-inline'"],
+    styleSrc: ["'self' 'unsafe-inline'"],
+    // objectSrc: ["'none'"], // only define to allow plugins, else let defaultSrc 'none' block it
+    formAction: ["'self'"],
+    frameAncestors: ["'none'"],
+    baseUri: ["'self'"],
+    pluginTypes: ["'none'"],
+    manifestSrc: ["'self'"],
+    frameSrc: ["'self'"], // instead of deprecated child-src / self because of test-embed
+    workerSrc: ["'self'"], // instead of deprecated child-src
+    upgradeInsecureRequests: true
+  },
+  (CONFIG.SERVICES['CSP-LOGGER'] != null) ? { reportUri: CONFIG.SERVICES['CSP-LOGGER'] } : {}
+)
+
+const baseCSP = helmet.contentSecurityPolicy({
+  directives: baseDirectives,
+  browserSniff: false,
+  reportOnly: true
+})
+
+const embedCSP = helmet.contentSecurityPolicy({
+  directives: Object.assign(baseDirectives, {
+    frameAncestors: ['*']
+  }),
+  browserSniff: false, // assumes a modern browser, but allows CDN in front
+  reportOnly: true
+})
+
+// ---------------------------------------------------------------------------
+
+export {
+  baseCSP,
+  embedCSP
+}
index cabad39c6cce5f2c696f0e80a882b93e085713ed..607def85552bb78d60ad5adde5c2f29a3136afda 100644 (file)
@@ -10,4 +10,4 @@ const advertiseDoNotTrack = (_, res, next) => {
 
 export {
   advertiseDoNotTrack
- }
+}
index 0cef26953d8a4557a1da5a4fdb03c43fa03f36a2..b758a8586b19fb89a3adf9697260ee76eb2c7048 100644 (file)
@@ -6,3 +6,5 @@ export * from './pagination'
 export * from './servers'
 export * from './sort'
 export * from './user-right'
+export * from './dnt'
+export * from './csp'
index cfc30632cbc2020abeef37239123aa77790ba90a..550f1ad80c2f18f9fd3968d980647fe93cf52e80 100644 (file)
@@ -101,9 +101,11 @@ transcoding:
     1080:
       __name: "PEERTUBE_TRANSCODING_1080P"
       __format: "json"
-    
 
 instance:
   name: "PEERTUBE_INSTANCE_NAME"
   description: "PEERTUBE_INSTANCE_DESCRIPTION"
   terms: "PEERTUBE_INSTANCE_TERMS"
+
+services:
+  csp-logger: "PEERTUBE_SERVICES_CSPLOGGER"