@middy/http-security-headers 3.0.0-alpha.3 → 3.0.0-alpha.7

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 (3) hide show
  1. package/README.md +23 -13
  2. package/index.js +2 -279
  3. package/package.json +4 -4
package/README.md CHANGED
@@ -1,27 +1,37 @@
1
- # Middy http-security-headers middleware
2
-
3
- <div align="center">
4
- <img alt="Middy logo" src="https://raw.githubusercontent.com/middyjs/middy/main/docs/img/middy-logo.png"/>
5
- </div>
6
-
7
1
  <div align="center">
2
+ <h1>Middy http-security-headers middleware</h1>
3
+ <img alt="Middy logo" src="https://raw.githubusercontent.com/middyjs/middy/main/docs/img/middy-logo.svg"/>
8
4
  <p><strong>HTTP security headers middleware for the middy framework, the stylish Node.js middleware engine for AWS Lambda</strong></p>
9
5
  <p>Applies best practice security headers to responses. It's a simplified port of [HelmetJS](https://helmetjs.github.io/). See HelmetJS documentation for more details.</p>
10
- </div>
11
-
12
- <div align="center">
13
6
  <p>
14
- <a href="http://badge.fury.io/js/%40middy%2Fhttp-security-headers">
7
+ <a href="https://www.npmjs.com/package/@middy/http-security-headers?activeTab=versions">
15
8
  <img src="https://badge.fury.io/js/%40middy%2Fhttp-security-headers.svg" alt="npm version" style="max-width:100%;">
16
9
  </a>
10
+ <a href="https://packagephobia.com/result?p=@middy/http-security-headers">
11
+ <img src="https://packagephobia.com/badge?p=@middy/http-security-headers" alt="npm install size" style="max-width:100%;">
12
+ </a>
13
+ <a href="https://github.com/middyjs/middy/actions">
14
+ <img src="https://github.com/middyjs/middy/workflows/Tests/badge.svg" alt="GitHub Actions test status badge" style="max-width:100%;">
15
+ </a>
16
+ <br/>
17
+ <a href="https://standardjs.com/">
18
+ <img src="https://img.shields.io/badge/code_style-standard-brightgreen.svg" alt="Standard Code Style" style="max-width:100%;">
19
+ </a>
17
20
  <a href="https://snyk.io/test/github/middyjs/middy">
18
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%;">
19
22
  </a>
20
- <a href="https://standardjs.com/">
21
- <img src="https://img.shields.io/badge/code_style-standard-brightgreen.svg" alt="Standard Code Style" style="max-width:100%;">
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%;">
25
+ </a>
26
+ <a href="https://bestpractices.coreinfrastructure.org/projects/5280">
27
+ <img src="https://bestpractices.coreinfrastructure.org/projects/5280/badge" alt="Core Infrastructure Initiative (CII) Best Practices" style="max-width:100%;">
22
28
  </a>
29
+ <br/>
23
30
  <a href="https://gitter.im/middyjs/Lobby">
24
- <img src="https://badges.gitter.im/gitterHQ/gitter.svg" alt="Chat on Gitter" style="max-width:100%;">
31
+ <img src="https://badges.gitter.im/gitterHQ/gitter.svg" alt="Chat on Gitter" style="max-width:100%;">
32
+ </a>
33
+ <a href="https://stackoverflow.com/questions/tagged/middy?sort=Newest&uqlId=35052">
34
+ <img src="https://img.shields.io/badge/StackOverflow-[middy]-yellow" alt="Ask questions on StackOverflow" style="max-width:100%;">
25
35
  </a>
26
36
  </p>
27
37
  </div>
package/index.js CHANGED
@@ -1,280 +1,3 @@
1
- import { normalizeHttpResponse } from '@middy/util'
1
+ import{normalizeHttpResponse}from'@middy/util';const defaults={contentSecurityPolicy:{'default-src':"'none'",'base-uri':"'none'",sandbox:'','form-action':"'none'",'frame-ancestors':"'none'",'navigate-to':"'none'",'report-to':'csp','require-trusted-types-for':"'script'",'trusted-types':"'none'",'upgrade-insecure-requests':''},contentTypeOptions:{action:'nosniff'},crossOriginEmbedderPolicy:{policy:'require-corp'},crossOriginOpenerPolicy:{policy:'same-origin'},crossOriginResourcePolicy:{policy:'same-origin'},dnsPrefetchControl:{allow:false},downloadOptions:{action:'noopen'},frameOptions:{action:'deny'},originAgentCluster:{},permissionsPolicy:{accelerometer:'','ambient-light-sensor':'',autoplay:'',battery:'',camera:'','cross-origin-isolated':'','display-capture':'','document-domain':'','encrypted-media':'','execution-while-not-rendered':'','execution-while-out-of-viewport':'',fullscreen:'',geolocation:'',gyroscope:'','keyboard-map':'',magnetometer:'',microphone:'',midi:'','navigation-override':'',payment:'','picture-in-picture':'','publickey-credentials-get':'','screen-wake-lock':'','sync-xhr':'',usb:'','web-share':'','xr-spatial-tracking':'','clipboard-read':'','clipboard-write':'',gamepad:'','speaker-selection':'','conversion-measurement':'','focus-without-user-activation':'',hid:'','idle-detection':'','interest-cohort':'',serial:'','sync-script':'','trust-token-redemption':'','window-placement':'','vertical-scroll':''},permittedCrossDomainPolicies:{policy:'none'},poweredBy:{server:''},referrerPolicy:{policy:'no-referrer'},reportTo:{maxAge:365*24*60*60,default:'',includeSubdomains:true,csp:'',staple:'',xss:''},strictTransportSecurity:{maxAge:180*24*60*60,includeSubDomains:true,preload:true},xssProtection:{reportTo:'xss'}};const helmet={};const helmetHtmlOnly={};helmetHtmlOnly.contentSecurityPolicy=(headers,config)=>{let header=Object.keys(config).map(policy=>config[policy]?`${policy} ${config[policy]}`:'').filter(str=>str).join('; ');if(config.sandbox===''){header+='; sandbox'}if(config['upgrade-insecure-requests']===''){header+='; upgrade-insecure-requests'}headers['Content-Security-Policy']=header};helmetHtmlOnly.crossOriginEmbedderPolicy=(headers,config)=>{headers['Cross-Origin-Embedder-Policy']=config.policy};helmetHtmlOnly.crossOriginOpenerPolicy=(headers,config)=>{headers['Cross-Origin-Opener-Policy']=config.policy};helmetHtmlOnly.crossOriginResourcePolicy=(headers,config)=>{headers['Cross-Origin-Resource-Policy']=config.policy};helmetHtmlOnly.permissionsPolicy=(headers,config)=>{headers['Permissions-Policy']=Object.keys(config).map(policy=>`${policy}=${config[policy]==='*'?'*':`(${config[policy]})`}`).join(', ')};helmet.originAgentCluster=(headers,config)=>{headers['Origin-Agent-Cluster']='?1'};helmet.referrerPolicy=(headers,config)=>{headers['Referrer-Policy']=config.policy};helmetHtmlOnly.reportTo=(headers,config)=>{headers['Report-To']=Object.keys(config).map(group=>config[group]&&group!=='includeSubdomains'?`{ "group": "default", "max_age": ${config.maxAge}, "endpoints": [ { "url": "${config[group]}" } ]${group==='default'?`, "include_subdomains": ${config.includeSubdomains}`:''} }`:'').filter(str=>str).join(', ')};helmet.strictTransportSecurity=(headers,config)=>{let header='max-age='+Math.round(config.maxAge);if(config.includeSubDomains){header+='; includeSubDomains'}if(config.preload){header+='; preload'}headers['Strict-Transport-Security']=header};helmet.contentTypeOptions=(headers,config)=>{headers['X-Content-Type-Options']=config.action};helmet.dnsPrefetchControl=(headers,config)=>{headers['X-DNS-Prefetch-Control']=config.allow?'on':'off'};helmet.downloadOptions=(headers,config)=>{headers['X-Download-Options']=config.action};helmetHtmlOnly.frameOptions=(headers,config)=>{headers['X-Frame-Options']=config.action.toUpperCase()};helmet.permittedCrossDomainPolicies=(headers,config)=>{headers['X-Permitted-Cross-Domain-Policies']=config.policy};helmet.poweredBy=(headers,config)=>{if(config.server){headers['X-Powered-By']=config.server}else{delete headers.Server;delete headers['X-Powered-By']}};helmetHtmlOnly.xssProtection=(headers,config)=>{let header='1; mode=block';if(config.reportTo){header+='; report='+config.reportTo}headers['X-XSS-Protection']=header};const httpSecurityHeadersMiddleware=(opts={})=>{const options={...defaults,...opts};const httpSecurityHeadersMiddlewareAfter=async request=>{normalizeHttpResponse(request);Object.keys(helmet).forEach(key=>{if(!options[key])return;const config={...defaults[key],...options[key]};helmet[key](request.response.headers,config)});if(request.response.headers['Content-Type']?.includes('text/html')){Object.keys(helmetHtmlOnly).forEach(key=>{if(!options[key])return;const config={...defaults[key],...options[key]};helmetHtmlOnly[key](request.response.headers,config)})}};const httpSecurityHeadersMiddlewareOnError=async request=>{if(request.response===undefined)return;return httpSecurityHeadersMiddlewareAfter(request)};return{after:httpSecurityHeadersMiddlewareAfter,onError:httpSecurityHeadersMiddlewareOnError}};export default httpSecurityHeadersMiddleware
2
2
 
3
- // Code and Defaults heavily based off https://helmetjs.github.io/
4
-
5
- const defaults = {
6
- contentSecurityPolicy: {
7
- // Fetch directives
8
- // 'child-src': '', // fallback default-src
9
- // 'connect-src': '', // fallback default-src
10
- 'default-src': "'none'",
11
- // 'font-src':'', // fallback default-src
12
- // 'frame-src':'', // fallback child-src > default-src
13
- // 'img-src':'', // fallback default-src
14
- // 'manifest-src':'', // fallback default-src
15
- // 'media-src':'', // fallback default-src
16
- // 'object-src':'', // fallback default-src
17
- // 'prefetch-src':'', // fallback default-src
18
- // 'script-src':'', // fallback default-src
19
- // 'script-src-elem':'', // fallback script-src > default-src
20
- // 'script-src-attr':'', // fallback script-src > default-src
21
- // 'style-src':'', // fallback default-src
22
- // 'style-src-elem':'', // fallback style-src > default-src
23
- // 'style-src-attr':'', // fallback style-src > default-src
24
- // 'worker-src':'', // fallback child-src > script-src > default-src
25
- // Document directives
26
- 'base-uri': "'none'",
27
- sandbox: '',
28
- // Navigation directives
29
- 'form-action': "'none'",
30
- 'frame-ancestors': "'none'",
31
- 'navigate-to': "'none'",
32
- // Reporting directives
33
- 'report-to': 'csp',
34
- // Other directives
35
- 'require-trusted-types-for': "'script'",
36
- 'trusted-types': "'none'",
37
- 'upgrade-insecure-requests': ''
38
- },
39
- contentTypeOptions: {
40
- action: 'nosniff'
41
- },
42
- crossOriginEmbedderPolicy: {
43
- policy: 'require-corp'
44
- },
45
- crossOriginOpenerPolicy: {
46
- policy: 'same-origin'
47
- },
48
- crossOriginResourcePolicy: {
49
- policy: 'same-origin'
50
- },
51
- dnsPrefetchControl: {
52
- allow: false
53
- },
54
- downloadOptions: {
55
- action: 'noopen'
56
- },
57
- frameOptions: {
58
- action: 'deny'
59
- },
60
- originAgentCluster: {},
61
- permissionsPolicy: {
62
- // Standard
63
- accelerometer: '',
64
- 'ambient-light-sensor': '',
65
- autoplay: '',
66
- battery: '',
67
- camera: '',
68
- 'cross-origin-isolated': '',
69
- 'display-capture': '',
70
- 'document-domain': '',
71
- 'encrypted-media': '',
72
- 'execution-while-not-rendered': '',
73
- 'execution-while-out-of-viewport': '',
74
- fullscreen: '',
75
- geolocation: '',
76
- gyroscope: '',
77
- 'keyboard-map': '',
78
- magnetometer: '',
79
- microphone: '',
80
- midi: '',
81
- 'navigation-override': '',
82
- payment: '',
83
- 'picture-in-picture': '',
84
- 'publickey-credentials-get': '',
85
- 'screen-wake-lock': '',
86
- 'sync-xhr': '',
87
- usb: '',
88
- 'web-share': '',
89
- 'xr-spatial-tracking': '',
90
- // Proposed
91
- 'clipboard-read': '',
92
- 'clipboard-write': '',
93
- gamepad: '',
94
- 'speaker-selection': '',
95
- // Experimental
96
- 'conversion-measurement': '',
97
- 'focus-without-user-activation': '',
98
- hid: '',
99
- 'idle-detection': '',
100
- 'interest-cohort': '',
101
- serial: '',
102
- 'sync-script': '',
103
- 'trust-token-redemption': '',
104
- 'window-placement': '',
105
- 'vertical-scroll': ''
106
- },
107
- permittedCrossDomainPolicies: {
108
- policy: 'none' // none, master-only, by-content-type, by-ftp-filename, all
109
- },
110
- poweredBy: {
111
- server: ''
112
- },
113
- referrerPolicy: {
114
- policy: 'no-referrer'
115
- },
116
- reportTo: {
117
- maxAge: 365 * 24 * 60 * 60,
118
- default: '',
119
- includeSubdomains: true,
120
- csp: '',
121
- staple: '',
122
- xss: ''
123
- },
124
- strictTransportSecurity: {
125
- maxAge: 180 * 24 * 60 * 60,
126
- includeSubDomains: true,
127
- preload: true
128
- },
129
- xssProtection: {
130
- reportTo: 'xss'
131
- }
132
- }
133
-
134
- const helmet = {}
135
- const helmetHtmlOnly = {}
136
-
137
- // *** https://github.com/helmetjs/helmet/tree/main/middlewares *** //
138
- // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
139
- helmetHtmlOnly.contentSecurityPolicy = (headers, config) => {
140
- let header = Object.keys(config)
141
- .map(policy => config[policy] ? `${policy} ${config[policy]}` : '')
142
- .filter(str => str)
143
- .join('; ')
144
- if (config.sandbox === '') {
145
- header += '; sandbox'
146
- }
147
- if (config['upgrade-insecure-requests'] === '') {
148
- header += '; upgrade-insecure-requests'
149
- }
150
- headers['Content-Security-Policy'] = header
151
- }
152
- // crossdomain - N/A - for Adobe products
153
- helmetHtmlOnly.crossOriginEmbedderPolicy = (headers, config) => {
154
- headers['Cross-Origin-Embedder-Policy'] = config.policy
155
- }
156
- helmetHtmlOnly.crossOriginOpenerPolicy = (headers, config) => {
157
- headers['Cross-Origin-Opener-Policy'] = config.policy
158
- }
159
- helmetHtmlOnly.crossOriginResourcePolicy = (headers, config) => {
160
- headers['Cross-Origin-Resource-Policy'] = config.policy
161
- }
162
-
163
- // expectCt - DEPRECATED
164
- // hpkp - DEPRECATED
165
-
166
- // https://www.permissionspolicy.com/
167
- helmetHtmlOnly.permissionsPolicy = (headers, config) => {
168
- headers['Permissions-Policy'] = Object.keys(config)
169
- .map(policy => `${policy}=${policy === '*' ? '*' : `(${config[policy]})`}`)
170
- .join(', ')
171
- }
172
-
173
- helmet.originAgentCluster = (headers, config) => {
174
- headers['Origin-Agent-Cluster'] = '?1'
175
- }
176
-
177
- // https://github.com/helmetjs/referrer-policy
178
- helmet.referrerPolicy = (headers, config) => {
179
- headers['Referrer-Policy'] = config.policy
180
- }
181
-
182
- helmetHtmlOnly.reportTo = (headers, config) => {
183
- headers['Report-To'] = Object.keys(config)
184
- .map(group => (config[group] && group !== 'includeSubdomains') ? `{ "group": "default", "max_age": ${config.maxAge}, "endpoints": [ { "url": "${config[group]}" } ]${group === 'default' ? `, "include_subdomains": ${config.includeSubdomains}` : ''} }` : '')
185
- .filter(str => str)
186
- .join(', ')
187
- }
188
-
189
- // https://github.com/helmetjs/hsts
190
- helmet.strictTransportSecurity = (headers, config) => {
191
- let header = 'max-age=' + Math.round(config.maxAge)
192
- if (config.includeSubDomains) {
193
- header += '; includeSubDomains'
194
- }
195
- if (config.preload) {
196
- header += '; preload'
197
- }
198
- headers['Strict-Transport-Security'] = header
199
- }
200
-
201
- // noCache - N/A - separate middleware
202
-
203
- // X-* //
204
- // https://github.com/helmetjs/dont-sniff-mimetype
205
- helmet.contentTypeOptions = (headers, config) => {
206
- headers['X-Content-Type-Options'] = config.action
207
- }
208
-
209
- // https://github.com/helmetjs/dns-Prefetch-control
210
- helmet.dnsPrefetchControl = (headers, config) => {
211
- headers['X-DNS-Prefetch-Control'] = config.allow ? 'on' : 'off'
212
- }
213
-
214
- // https://github.com/helmetjs/ienoopen
215
- helmet.downloadOptions = (headers, config) => {
216
- headers['X-Download-Options'] = config.action
217
- }
218
-
219
- // https://github.com/helmetjs/frameOptions
220
- helmetHtmlOnly.frameOptions = (headers, config) => {
221
- headers['X-Frame-Options'] = config.action.toUpperCase()
222
- }
223
-
224
- // https://github.com/helmetjs/crossdomain
225
- helmet.permittedCrossDomainPolicies = (headers, config) => {
226
- headers['X-Permitted-Cross-Domain-Policies'] = config.policy
227
- }
228
-
229
- // https://github.com/helmetjs/hide-powered-by
230
- helmet.poweredBy = (headers, config) => {
231
- if (config.server) {
232
- headers['X-Powered-By'] = config.server
233
- } else {
234
- delete headers.Server
235
- delete headers['X-Powered-By']
236
- }
237
- }
238
-
239
- // https://github.com/helmetjs/x-xss-protection
240
- helmetHtmlOnly.xssProtection = (headers, config) => {
241
- let header = '1; mode=block'
242
- if (config.reportTo) {
243
- header += '; report=' + config.reportTo
244
- }
245
- headers['X-XSS-Protection'] = header
246
- }
247
-
248
- const httpSecurityHeadersMiddleware = (opts = {}) => {
249
- const options = { ...defaults, ...opts }
250
-
251
- const httpSecurityHeadersMiddlewareAfter = async (request) => {
252
- normalizeHttpResponse(request)
253
-
254
- Object.keys(helmet).forEach((key) => {
255
- if (!options[key]) return
256
- const config = { ...defaults[key], ...options[key] }
257
- helmet[key](request.response.headers, config)
258
- })
259
-
260
- if (request.response.headers['Content-Type']?.includes('text/html')) {
261
- Object.keys(helmetHtmlOnly).forEach((key) => {
262
- if (!options[key]) return
263
- const config = { ...defaults[key], ...options[key] }
264
- helmetHtmlOnly[key](
265
- request.response.headers,
266
- config
267
- )
268
- })
269
- }
270
- }
271
- const httpSecurityHeadersMiddlewareOnError = async (request) => {
272
- if (request.response === undefined) return
273
- return httpSecurityHeadersMiddlewareAfter(request)
274
- }
275
- return {
276
- after: httpSecurityHeadersMiddlewareAfter,
277
- onError: httpSecurityHeadersMiddlewareOnError
278
- }
279
- }
280
- export default httpSecurityHeadersMiddleware
3
+ //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@middy/http-security-headers",
3
- "version": "3.0.0-alpha.3",
3
+ "version": "3.0.0-alpha.7",
4
4
  "description": "Applies best practice security headers to responses. It's a simplified port of HelmetJS",
5
5
  "type": "module",
6
6
  "engines": {
@@ -50,11 +50,11 @@
50
50
  "url": "https://github.com/middyjs/middy/issues"
51
51
  },
52
52
  "homepage": "https://github.com/middyjs/middy#readme",
53
- "gitHead": "1441158711580313765e6d156046ef0fade0d156",
53
+ "gitHead": "5cef39ebe49c201f97d71bb0680004de4b82cb91",
54
54
  "dependencies": {
55
- "@middy/util": "^3.0.0-alpha.3"
55
+ "@middy/util": "^3.0.0-alpha.7"
56
56
  },
57
57
  "devDependencies": {
58
- "@middy/core": "^3.0.0-alpha.3"
58
+ "@middy/core": "^3.0.0-alpha.7"
59
59
  }
60
60
  }