@middy/http-security-headers 5.0.0-alpha.0 → 5.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +3 -2
  2. package/index.js +44 -2
  3. package/package.json +4 -10
  4. package/index.cjs +0 -226
package/README.md CHANGED
@@ -20,8 +20,9 @@
20
20
  <a href="https://snyk.io/test/github/middyjs/middy">
21
21
  <img src="https://snyk.io/test/github/middyjs/middy/badge.svg" alt="Known Vulnerabilities" data-canonical-src="https://snyk.io/test/github/middyjs/middy" style="max-width:100%;">
22
22
  </a>
23
- <a href="https://lgtm.com/projects/g/middyjs/middy/context:javascript">
24
- <img src="https://img.shields.io/lgtm/grade/javascript/g/middyjs/middy.svg?logo=lgtm&logoWidth=18" alt="Language grade: JavaScript" style="max-width:100%;">
23
+ <a href="https://github.com/middyjs/middy/actions/workflows/sast.yml">
24
+ <img src="https://github.com/middyjs/middy/actions/workflows/sast.yml/badge.svg
25
+ ?branch=main&event=push" alt="CodeQL" style="max-width:100%;">
25
26
  </a>
26
27
  <a href="https://bestpractices.coreinfrastructure.org/projects/5280">
27
28
  <img src="https://bestpractices.coreinfrastructure.org/projects/5280/badge" alt="Core Infrastructure Initiative (CII) Best Practices" style="max-width:100%;">
package/index.js CHANGED
@@ -1,13 +1,35 @@
1
1
  import { normalizeHttpResponse } from '@middy/util';
2
+ // Code and Defaults heavily based off https://helmetjs.github.io/
2
3
  const defaults = {
3
4
  contentSecurityPolicy: {
5
+ // Fetch directives
6
+ // 'child-src': '', // fallback default-src
7
+ // 'connect-src': '', // fallback default-src
4
8
  'default-src': "'none'",
9
+ // 'font-src':'', // fallback default-src
10
+ // 'frame-src':'', // fallback child-src > default-src
11
+ // 'img-src':'', // fallback default-src
12
+ // 'manifest-src':'', // fallback default-src
13
+ // 'media-src':'', // fallback default-src
14
+ // 'object-src':'', // fallback default-src
15
+ // 'prefetch-src':'', // fallback default-src
16
+ // 'script-src':'', // fallback default-src
17
+ // 'script-src-elem':'', // fallback script-src > default-src
18
+ // 'script-src-attr':'', // fallback script-src > default-src
19
+ // 'style-src':'', // fallback default-src
20
+ // 'style-src-elem':'', // fallback style-src > default-src
21
+ // 'style-src-attr':'', // fallback style-src > default-src
22
+ // 'worker-src':'', // fallback child-src > script-src > default-src
23
+ // Document directives
5
24
  'base-uri': "'none'",
6
25
  sandbox: '',
26
+ // Navigation directives
7
27
  'form-action': "'none'",
8
28
  'frame-ancestors': "'none'",
9
29
  'navigate-to': "'none'",
30
+ // Reporting directives
10
31
  'report-to': 'csp',
32
+ // Other directives
11
33
  'require-trusted-types-for': "'script'",
12
34
  'trusted-types': "'none'",
13
35
  'upgrade-insecure-requests': ''
@@ -35,6 +57,7 @@ const defaults = {
35
57
  },
36
58
  originAgentCluster: {},
37
59
  permissionsPolicy: {
60
+ // Standard
38
61
  accelerometer: '',
39
62
  'ambient-light-sensor': '',
40
63
  autoplay: '',
@@ -62,10 +85,12 @@ const defaults = {
62
85
  usb: '',
63
86
  'web-share': '',
64
87
  'xr-spatial-tracking': '',
88
+ // Proposed
65
89
  'clipboard-read': '',
66
90
  'clipboard-write': '',
67
91
  gamepad: '',
68
92
  'speaker-selection': '',
93
+ // Experimental
69
94
  'conversion-measurement': '',
70
95
  'focus-without-user-activation': '',
71
96
  hid: '',
@@ -78,7 +103,7 @@ const defaults = {
78
103
  'vertical-scroll': ''
79
104
  },
80
105
  permittedCrossDomainPolicies: {
81
- policy: 'none'
106
+ policy: 'none' // none, master-only, by-content-type, by-ftp-filename, all
82
107
  },
83
108
  poweredBy: {
84
109
  server: ''
@@ -105,6 +130,8 @@ const defaults = {
105
130
  };
106
131
  const helmet = {};
107
132
  const helmetHtmlOnly = {};
133
+ // *** https://github.com/helmetjs/helmet/tree/main/middlewares *** //
134
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
108
135
  helmetHtmlOnly.contentSecurityPolicy = (headers, config)=>{
109
136
  let header = Object.keys(config).map((policy)=>config[policy] ? `${policy} ${config[policy]}` : '').filter((str)=>str).join('; ');
110
137
  if (config.sandbox === '') {
@@ -115,6 +142,7 @@ helmetHtmlOnly.contentSecurityPolicy = (headers, config)=>{
115
142
  }
116
143
  headers['Content-Security-Policy'] = header;
117
144
  };
145
+ // crossdomain - N/A - for Adobe products
118
146
  helmetHtmlOnly.crossOriginEmbedderPolicy = (headers, config)=>{
119
147
  headers['Cross-Origin-Embedder-Policy'] = config.policy;
120
148
  };
@@ -124,12 +152,16 @@ helmetHtmlOnly.crossOriginOpenerPolicy = (headers, config)=>{
124
152
  helmetHtmlOnly.crossOriginResourcePolicy = (headers, config)=>{
125
153
  headers['Cross-Origin-Resource-Policy'] = config.policy;
126
154
  };
155
+ // DEPRECATED: expectCt
156
+ // DEPRECATED: hpkp
157
+ // https://www.permissionspolicy.com/
127
158
  helmetHtmlOnly.permissionsPolicy = (headers, config)=>{
128
159
  headers['Permissions-Policy'] = Object.keys(config).map((policy)=>`${policy}=${config[policy] === '*' ? '*' : '(' + config[policy] + ')'}`).join(', ');
129
160
  };
130
161
  helmet.originAgentCluster = (headers, config)=>{
131
162
  headers['Origin-Agent-Cluster'] = '?1';
132
163
  };
164
+ // https://github.com/helmetjs/referrer-policy
133
165
  helmet.referrerPolicy = (headers, config)=>{
134
166
  headers['Referrer-Policy'] = config.policy;
135
167
  };
@@ -139,6 +171,7 @@ helmetHtmlOnly.reportTo = (headers, config)=>{
139
171
  return config[group] && group !== 'includeSubdomains' ? `{ "group": "default", "max_age": ${config.maxAge}, "endpoints": [ { "url": "${config[group]}" } ]${includeSubdomains} }` : '';
140
172
  }).filter((str)=>str).join(', ');
141
173
  };
174
+ // https://github.com/helmetjs/hsts
142
175
  helmet.strictTransportSecurity = (headers, config)=>{
143
176
  let header = 'max-age=' + Math.round(config.maxAge);
144
177
  if (config.includeSubDomains) {
@@ -149,21 +182,29 @@ helmet.strictTransportSecurity = (headers, config)=>{
149
182
  }
150
183
  headers['Strict-Transport-Security'] = header;
151
184
  };
185
+ // noCache - N/A - separate middleware
186
+ // X-* //
187
+ // https://github.com/helmetjs/dont-sniff-mimetype
152
188
  helmet.contentTypeOptions = (headers, config)=>{
153
189
  headers['X-Content-Type-Options'] = config.action;
154
190
  };
191
+ // https://github.com/helmetjs/dns-Prefetch-control
155
192
  helmet.dnsPrefetchControl = (headers, config)=>{
156
193
  headers['X-DNS-Prefetch-Control'] = config.allow ? 'on' : 'off';
157
194
  };
195
+ // https://github.com/helmetjs/ienoopen
158
196
  helmet.downloadOptions = (headers, config)=>{
159
197
  headers['X-Download-Options'] = config.action;
160
198
  };
199
+ // https://github.com/helmetjs/frameOptions
161
200
  helmetHtmlOnly.frameOptions = (headers, config)=>{
162
201
  headers['X-Frame-Options'] = config.action.toUpperCase();
163
202
  };
203
+ // https://github.com/helmetjs/crossdomain
164
204
  helmet.permittedCrossDomainPolicies = (headers, config)=>{
165
205
  headers['X-Permitted-Cross-Domain-Policies'] = config.policy;
166
206
  };
207
+ // https://github.com/helmetjs/hide-powered-by
167
208
  helmet.poweredBy = (headers, config)=>{
168
209
  if (config.server) {
169
210
  headers['X-Powered-By'] = config.server;
@@ -172,6 +213,7 @@ helmet.poweredBy = (headers, config)=>{
172
213
  delete headers['X-Powered-By'];
173
214
  }
174
215
  };
216
+ // https://github.com/helmetjs/x-xss-protection
175
217
  helmetHtmlOnly.xssProtection = (headers, config)=>{
176
218
  let header = '1; mode=block';
177
219
  if (config.reportTo) {
@@ -207,7 +249,7 @@ const httpSecurityHeadersMiddleware = (opts = {})=>{
207
249
  };
208
250
  const httpSecurityHeadersMiddlewareOnError = async (request)=>{
209
251
  if (request.response === undefined) return;
210
- return httpSecurityHeadersMiddlewareAfter(request);
252
+ await httpSecurityHeadersMiddlewareAfter(request);
211
253
  };
212
254
  return {
213
255
  after: httpSecurityHeadersMiddlewareAfter,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@middy/http-security-headers",
3
- "version": "5.0.0-alpha.0",
3
+ "version": "5.0.0-alpha.2",
4
4
  "description": "Applies best practice security headers to responses. It's a simplified port of HelmetJS",
5
5
  "type": "module",
6
6
  "engines": {
@@ -10,24 +10,18 @@
10
10
  "publishConfig": {
11
11
  "access": "public"
12
12
  },
13
- "main": "./index.cjs",
14
13
  "module": "./index.js",
15
14
  "exports": {
16
15
  ".": {
17
16
  "import": {
18
17
  "types": "./index.d.ts",
19
18
  "default": "./index.js"
20
- },
21
- "require": {
22
- "types": "./index.d.ts",
23
- "default": "./index.cjs"
24
19
  }
25
20
  }
26
21
  },
27
22
  "types": "index.d.ts",
28
23
  "files": [
29
24
  "index.js",
30
- "index.cjs",
31
25
  "index.d.ts"
32
26
  ],
33
27
  "scripts": {
@@ -68,11 +62,11 @@
68
62
  "type": "github",
69
63
  "url": "https://github.com/sponsors/willfarrell"
70
64
  },
71
- "gitHead": "08c35e3dba9efdad0b86666ce206ce302cc65d07",
65
+ "gitHead": "ebce8d5df8783077fa49ba62ee9be20e8486a7f1",
72
66
  "dependencies": {
73
- "@middy/util": "5.0.0-alpha.0"
67
+ "@middy/util": "5.0.0-alpha.2"
74
68
  },
75
69
  "devDependencies": {
76
- "@middy/core": "5.0.0-alpha.0"
70
+ "@middy/core": "5.0.0-alpha.2"
77
71
  }
78
72
  }
package/index.cjs DELETED
@@ -1,226 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(module, "exports", {
6
- enumerable: true,
7
- get: ()=>_default
8
- });
9
- const _util = require("@middy/util");
10
- const defaults = {
11
- contentSecurityPolicy: {
12
- 'default-src': "'none'",
13
- 'base-uri': "'none'",
14
- sandbox: '',
15
- 'form-action': "'none'",
16
- 'frame-ancestors': "'none'",
17
- 'navigate-to': "'none'",
18
- 'report-to': 'csp',
19
- 'require-trusted-types-for': "'script'",
20
- 'trusted-types': "'none'",
21
- 'upgrade-insecure-requests': ''
22
- },
23
- contentTypeOptions: {
24
- action: 'nosniff'
25
- },
26
- crossOriginEmbedderPolicy: {
27
- policy: 'require-corp'
28
- },
29
- crossOriginOpenerPolicy: {
30
- policy: 'same-origin'
31
- },
32
- crossOriginResourcePolicy: {
33
- policy: 'same-origin'
34
- },
35
- dnsPrefetchControl: {
36
- allow: false
37
- },
38
- downloadOptions: {
39
- action: 'noopen'
40
- },
41
- frameOptions: {
42
- action: 'deny'
43
- },
44
- originAgentCluster: {},
45
- permissionsPolicy: {
46
- accelerometer: '',
47
- 'ambient-light-sensor': '',
48
- autoplay: '',
49
- battery: '',
50
- camera: '',
51
- 'cross-origin-isolated': '',
52
- 'display-capture': '',
53
- 'document-domain': '',
54
- 'encrypted-media': '',
55
- 'execution-while-not-rendered': '',
56
- 'execution-while-out-of-viewport': '',
57
- fullscreen: '',
58
- geolocation: '',
59
- gyroscope: '',
60
- 'keyboard-map': '',
61
- magnetometer: '',
62
- microphone: '',
63
- midi: '',
64
- 'navigation-override': '',
65
- payment: '',
66
- 'picture-in-picture': '',
67
- 'publickey-credentials-get': '',
68
- 'screen-wake-lock': '',
69
- 'sync-xhr': '',
70
- usb: '',
71
- 'web-share': '',
72
- 'xr-spatial-tracking': '',
73
- 'clipboard-read': '',
74
- 'clipboard-write': '',
75
- gamepad: '',
76
- 'speaker-selection': '',
77
- 'conversion-measurement': '',
78
- 'focus-without-user-activation': '',
79
- hid: '',
80
- 'idle-detection': '',
81
- 'interest-cohort': '',
82
- serial: '',
83
- 'sync-script': '',
84
- 'trust-token-redemption': '',
85
- 'window-placement': '',
86
- 'vertical-scroll': ''
87
- },
88
- permittedCrossDomainPolicies: {
89
- policy: 'none'
90
- },
91
- poweredBy: {
92
- server: ''
93
- },
94
- referrerPolicy: {
95
- policy: 'no-referrer'
96
- },
97
- reportTo: {
98
- maxAge: 365 * 24 * 60 * 60,
99
- default: '',
100
- includeSubdomains: true,
101
- csp: '',
102
- staple: '',
103
- xss: ''
104
- },
105
- strictTransportSecurity: {
106
- maxAge: 180 * 24 * 60 * 60,
107
- includeSubDomains: true,
108
- preload: true
109
- },
110
- xssProtection: {
111
- reportTo: 'xss'
112
- }
113
- };
114
- const helmet = {};
115
- const helmetHtmlOnly = {};
116
- helmetHtmlOnly.contentSecurityPolicy = (headers, config)=>{
117
- let header = Object.keys(config).map((policy)=>config[policy] ? `${policy} ${config[policy]}` : '').filter((str)=>str).join('; ');
118
- if (config.sandbox === '') {
119
- header += '; sandbox';
120
- }
121
- if (config['upgrade-insecure-requests'] === '') {
122
- header += '; upgrade-insecure-requests';
123
- }
124
- headers['Content-Security-Policy'] = header;
125
- };
126
- helmetHtmlOnly.crossOriginEmbedderPolicy = (headers, config)=>{
127
- headers['Cross-Origin-Embedder-Policy'] = config.policy;
128
- };
129
- helmetHtmlOnly.crossOriginOpenerPolicy = (headers, config)=>{
130
- headers['Cross-Origin-Opener-Policy'] = config.policy;
131
- };
132
- helmetHtmlOnly.crossOriginResourcePolicy = (headers, config)=>{
133
- headers['Cross-Origin-Resource-Policy'] = config.policy;
134
- };
135
- helmetHtmlOnly.permissionsPolicy = (headers, config)=>{
136
- headers['Permissions-Policy'] = Object.keys(config).map((policy)=>`${policy}=${config[policy] === '*' ? '*' : '(' + config[policy] + ')'}`).join(', ');
137
- };
138
- helmet.originAgentCluster = (headers, config)=>{
139
- headers['Origin-Agent-Cluster'] = '?1';
140
- };
141
- helmet.referrerPolicy = (headers, config)=>{
142
- headers['Referrer-Policy'] = config.policy;
143
- };
144
- helmetHtmlOnly.reportTo = (headers, config)=>{
145
- headers['Report-To'] = Object.keys(config).map((group)=>{
146
- const includeSubdomains = group === 'default' ? `, "include_subdomains": ${config.includeSubdomains}` : '';
147
- return config[group] && group !== 'includeSubdomains' ? `{ "group": "default", "max_age": ${config.maxAge}, "endpoints": [ { "url": "${config[group]}" } ]${includeSubdomains} }` : '';
148
- }).filter((str)=>str).join(', ');
149
- };
150
- helmet.strictTransportSecurity = (headers, config)=>{
151
- let header = 'max-age=' + Math.round(config.maxAge);
152
- if (config.includeSubDomains) {
153
- header += '; includeSubDomains';
154
- }
155
- if (config.preload) {
156
- header += '; preload';
157
- }
158
- headers['Strict-Transport-Security'] = header;
159
- };
160
- helmet.contentTypeOptions = (headers, config)=>{
161
- headers['X-Content-Type-Options'] = config.action;
162
- };
163
- helmet.dnsPrefetchControl = (headers, config)=>{
164
- headers['X-DNS-Prefetch-Control'] = config.allow ? 'on' : 'off';
165
- };
166
- helmet.downloadOptions = (headers, config)=>{
167
- headers['X-Download-Options'] = config.action;
168
- };
169
- helmetHtmlOnly.frameOptions = (headers, config)=>{
170
- headers['X-Frame-Options'] = config.action.toUpperCase();
171
- };
172
- helmet.permittedCrossDomainPolicies = (headers, config)=>{
173
- headers['X-Permitted-Cross-Domain-Policies'] = config.policy;
174
- };
175
- helmet.poweredBy = (headers, config)=>{
176
- if (config.server) {
177
- headers['X-Powered-By'] = config.server;
178
- } else {
179
- delete headers.Server;
180
- delete headers['X-Powered-By'];
181
- }
182
- };
183
- helmetHtmlOnly.xssProtection = (headers, config)=>{
184
- let header = '1; mode=block';
185
- if (config.reportTo) {
186
- header += '; report=' + config.reportTo;
187
- }
188
- headers['X-XSS-Protection'] = header;
189
- };
190
- const httpSecurityHeadersMiddleware = (opts = {})=>{
191
- const options = {
192
- ...defaults,
193
- ...opts
194
- };
195
- const httpSecurityHeadersMiddlewareAfter = async (request)=>{
196
- (0, _util.normalizeHttpResponse)(request);
197
- Object.keys(helmet).forEach((key)=>{
198
- if (!options[key]) return;
199
- const config = {
200
- ...defaults[key],
201
- ...options[key]
202
- };
203
- helmet[key](request.response.headers, config);
204
- });
205
- if (request.response.headers['Content-Type']?.includes('text/html')) {
206
- Object.keys(helmetHtmlOnly).forEach((key)=>{
207
- if (!options[key]) return;
208
- const config = {
209
- ...defaults[key],
210
- ...options[key]
211
- };
212
- helmetHtmlOnly[key](request.response.headers, config);
213
- });
214
- }
215
- };
216
- const httpSecurityHeadersMiddlewareOnError = async (request)=>{
217
- if (request.response === undefined) return;
218
- return httpSecurityHeadersMiddlewareAfter(request);
219
- };
220
- return {
221
- after: httpSecurityHeadersMiddlewareAfter,
222
- onError: httpSecurityHeadersMiddlewareOnError
223
- };
224
- };
225
- const _default = httpSecurityHeadersMiddleware;
226
-