فهرست منبع

Merge pull request #10966 from overleaf/td-add-coop-header

Upgrade Helmet to add some security-related response headers, including COOP

GitOrigin-RevId: fce8538b004f7b3ba6c6ca65ad311957d75b496a
Tim Down 3 سال پیش
والد
کامیت
9ab12f3b44

+ 15 - 2
package-lock.json

@@ -35741,7 +35741,7 @@
         "fuse.js": "^3.0.0",
         "globby": "^5.0.0",
         "handlebars": "^4.7.7",
-        "helmet": "^3.22.0",
+        "helmet": "^6.0.1",
         "http-proxy": "^1.18.1",
         "i18next": "^19.6.3",
         "i18next-fs-backend": "^1.0.7",
@@ -37189,6 +37189,14 @@
         "node": ">=12.0.0"
       }
     },
+    "services/web/node_modules/helmet": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/helmet/-/helmet-6.0.1.tgz",
+      "integrity": "sha512-8wo+VdQhTMVBMCITYZaGTbE4lvlthelPYSvoyNvk4RECTmrVjMerp9RfUOQXZWLvCcAn1pKj7ZRxK4lI9Alrcw==",
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
     "services/web/node_modules/http-errors": {
       "version": "1.7.2",
       "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
@@ -46214,7 +46222,7 @@
         "globby": "^5.0.0",
         "handlebars": "^4.7.7",
         "handlebars-loader": "^1.7.1",
-        "helmet": "^3.22.0",
+        "helmet": "^6.0.1",
         "html-webpack-plugin": "^5.5.0",
         "http-proxy": "^1.18.1",
         "i18next": "^19.6.3",
@@ -47262,6 +47270,11 @@
             "jws": "^4.0.0"
           }
         },
+        "helmet": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/helmet/-/helmet-6.0.1.tgz",
+          "integrity": "sha512-8wo+VdQhTMVBMCITYZaGTbE4lvlthelPYSvoyNvk4RECTmrVjMerp9RfUOQXZWLvCcAn1pKj7ZRxK4lI9Alrcw=="
+        },
         "http-errors": {
           "version": "1.7.2",
           "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",

+ 8 - 0
services/web/app/src/infrastructure/Server.js

@@ -269,6 +269,14 @@ webRouter.use(
     dnsPrefetchControl: false,
     referrerPolicy: { policy: 'origin-when-cross-origin' },
     hsts: false,
+    // Disabled because it's impractical to include every resource via CORS or
+    // with the magic CORP header
+    crossOriginEmbedderPolicy: false,
+    // Disabled because it's not a security header and has possibly-unwanted
+    // effects
+    originAgentCluster: false,
+    // We have custom handling for CSP below, so Helmet's default is disabled
+    contentSecurityPolicy: false,
   })
 )
 

+ 1 - 1
services/web/package.json

@@ -164,7 +164,7 @@
     "fuse.js": "^3.0.0",
     "globby": "^5.0.0",
     "handlebars": "^4.7.7",
-    "helmet": "^3.22.0",
+    "helmet": "^6.0.1",
     "http-proxy": "^1.18.1",
     "i18next": "^19.6.3",
     "i18next-fs-backend": "^1.0.7",

+ 24 - 18
services/web/test/acceptance/src/SecurityHeadersTests.js

@@ -19,32 +19,38 @@ const request = require('./helpers/request')
 
 const assert_has_common_headers = function (response) {
   const { headers } = response
-  assert.equal(headers['x-download-options'], 'noopen')
-  assert.equal(headers['x-xss-protection'], '1; mode=block')
-  return assert.equal(headers['referrer-policy'], 'origin-when-cross-origin')
+  assert.include(headers, {
+    'x-download-options': 'noopen',
+    'x-xss-protection': '0',
+    'cross-origin-resource-policy': 'same-origin',
+    'cross-origin-opener-policy': 'same-origin',
+    'x-content-type-options': 'nosniff',
+    'x-permitted-cross-domain-policies': 'none',
+    'referrer-policy': 'origin-when-cross-origin',
+  })
+  assert.isUndefined(headers['cross-origin-embedder-policy'])
 }
 
 const assert_has_cache_headers = function (response) {
-  const { headers } = response
-  assert.equal(headers['surrogate-control'], 'no-store')
-  assert.equal(
-    headers['cache-control'],
-    'no-store, no-cache, must-revalidate, proxy-revalidate'
-  )
-  assert.equal(headers.pragma, 'no-cache')
-  return assert.equal(headers.expires, '0')
+  assert.include(response.headers, {
+    'surrogate-control': 'no-store',
+    'cache-control': 'no-store, no-cache, must-revalidate, proxy-revalidate',
+    pragma: 'no-cache',
+    expires: '0',
+  })
 }
 
 const assert_has_no_cache_headers = function (response) {
-  const { headers } = response
-  assert.isUndefined(headers['surrogate-control'])
-  assert.isUndefined(headers['cache-control'])
-  assert.isUndefined(headers.pragma)
-  return assert.isUndefined(headers.expires)
+  assert.doesNotHaveAnyKeys(response.headers, [
+    'surrogate-control',
+    'cache-control',
+    'pragma',
+    'expires',
+  ])
 }
+
 const assert_has_asset_caching_headers = function (response) {
-  const { headers } = response
-  assert.equal(headers['cache-control'], 'public, max-age=31536000')
+  assert.equal(response.headers['cache-control'], 'public, max-age=31536000')
 }
 
 describe('SecurityHeaders', function () {