feat(vue-renderer): add csp meta tags (#5354)

This commit is contained in:
James George 2019-04-02 01:29:58 +05:30 committed by Pooya Parsa
parent 57a673d95f
commit b978a3761d
3 changed files with 25 additions and 22 deletions

View File

@ -3,7 +3,6 @@ import fs from 'fs'
import defaultsDeep from 'lodash/defaultsDeep' import defaultsDeep from 'lodash/defaultsDeep'
import defaults from 'lodash/defaults' import defaults from 'lodash/defaults'
import pick from 'lodash/pick' import pick from 'lodash/pick'
import isObject from 'lodash/isObject'
import uniq from 'lodash/uniq' import uniq from 'lodash/uniq'
import consola from 'consola' import consola from 'consola'
import { guardDir, isNonEmptyString, isPureObject, isUrl, getMainModule } from '@nuxt/utils' import { guardDir, isNonEmptyString, isPureObject, isUrl, getMainModule } from '@nuxt/utils'
@ -179,16 +178,14 @@ export function getNuxtConfig(_options) {
} }
// Apply default hash to CSP option // Apply default hash to CSP option
const { csp } = options.render if (options.render.csp) {
options.render.csp = defaults({}, options.render.csp, {
const cspDefaults = { hashAlgorithm: 'sha256',
hashAlgorithm: 'sha256', allowedSources: undefined,
allowedSources: undefined, policies: undefined,
policies: undefined, addMeta: Boolean(options._generate),
reportOnly: options.debug reportOnly: options.debug
} })
if (csp) {
options.render.csp = defaults(isObject(csp) ? csp : {}, cspDefaults)
} }
// cssSourceMap // cssSourceMap

View File

@ -81,6 +81,7 @@ describe('config: options', () => {
const { render: { csp } } = getNuxtConfig({ render: { csp: { allowedSources: true, test: true } } }) const { render: { csp } } = getNuxtConfig({ render: { csp: { allowedSources: true, test: true } } })
expect(csp).toEqual({ expect(csp).toEqual({
hashAlgorithm: 'sha256', hashAlgorithm: 'sha256',
addMeta: false,
allowedSources: true, allowedSources: true,
policies: undefined, policies: undefined,
reportOnly: false, reportOnly: false,

View File

@ -407,21 +407,26 @@ export default class VueRenderer {
APP += `<script>${serializedSession}</script>` APP += `<script>${serializedSession}</script>`
// Calculate CSP hashes // Calculate CSP hashes
const { csp } = this.context.options.render
const cspScriptSrcHashes = [] const cspScriptSrcHashes = []
const csp = this.context.options.render.csp if (csp) {
const containsUnsafeInlineScriptSrc = csp && csp.policies && csp.policies['script-src'] && csp.policies['script-src'].includes(`'unsafe-inline'`) // Only add the hash if 'unsafe-inline' rule isn't present to avoid conflicts (#5387)
const containsUnsafeInlineScriptSrc = csp.policies && csp.policies['script-src'] && csp.policies['script-src'].includes(`'unsafe-inline'`)
if (!containsUnsafeInlineScriptSrc) {
const hash = crypto.createHash(csp.hashAlgorithm)
hash.update(serializedSession)
cspScriptSrcHashes.push(`'${csp.hashAlgorithm}-${hash.digest('base64')}'`)
}
// Only add the hash if 'unsafe-inline' rule isn't present to avoid conflicts (#5387) // Call ssr:csp hook
if (csp && !containsUnsafeInlineScriptSrc) { await this.context.nuxt.callHook('vue-renderer:ssr:csp', cspScriptSrcHashes)
const { hashAlgorithm } = this.context.options.render.csp
const hash = crypto.createHash(hashAlgorithm) // Add csp meta tags
hash.update(serializedSession) if (csp.addMeta) {
cspScriptSrcHashes.push(`'${hashAlgorithm}-${hash.digest('base64')}'`) HEAD += `<meta http-equiv="Content-Security-Policy" content="script-src ${cspScriptSrcHashes.join()}">`
}
} }
// Call ssr:csp hook
await this.context.nuxt.callHook('vue-renderer:ssr:csp', cspScriptSrcHashes)
// Prepend scripts // Prepend scripts
APP += this.renderScripts(context) APP += this.renderScripts(context)
APP += m.script.text({ body: true }) APP += m.script.text({ body: true })