mirror of
https://github.com/nuxt/nuxt.git
synced 2025-02-17 06:01:34 +00:00
feat(server): support csp report-uri
(#7307)
This commit is contained in:
parent
c2c7081dc2
commit
37271f8ac4
@ -70,9 +70,10 @@ export default ({ options, nuxt, renderRoute, resources }) => async function nux
|
||||
|
||||
if (options.render.csp && cspScriptSrcHashes) {
|
||||
const { allowedSources, policies } = options.render.csp
|
||||
const cspHeader = options.render.csp.reportOnly ? 'Content-Security-Policy-Report-Only' : 'Content-Security-Policy'
|
||||
const isReportOnly = !!options.render.csp.reportOnly
|
||||
const cspHeader = isReportOnly ? 'Content-Security-Policy-Report-Only' : 'Content-Security-Policy'
|
||||
|
||||
res.setHeader(cspHeader, getCspString({ cspScriptSrcHashes, allowedSources, policies, isDev: options.dev }))
|
||||
res.setHeader(cspHeader, getCspString({ cspScriptSrcHashes, allowedSources, policies, isDev: options.dev, isReportOnly }))
|
||||
}
|
||||
|
||||
// Send response
|
||||
@ -123,20 +124,18 @@ const defaultPushAssets = (preloadFiles, shouldPush, publicPath, options) => {
|
||||
return links
|
||||
}
|
||||
|
||||
const getCspString = ({ cspScriptSrcHashes, allowedSources, policies, isDev }) => {
|
||||
const getCspString = ({ cspScriptSrcHashes, allowedSources, policies, isDev, isReportOnly }) => {
|
||||
const joinedHashes = cspScriptSrcHashes.join(' ')
|
||||
const baseCspStr = `script-src 'self'${isDev ? ' \'unsafe-eval\'' : ''} ${joinedHashes}`
|
||||
const policyObjectAvailable = typeof policies === 'object' && policies !== null && !Array.isArray(policies)
|
||||
|
||||
if (Array.isArray(allowedSources) && allowedSources.length) {
|
||||
return `${baseCspStr} ${allowedSources.join(' ')}`
|
||||
return isReportOnly && policyObjectAvailable && !!policies['report-uri'] ? `${baseCspStr} ${allowedSources.join(' ')}; report-uri ${policies['report-uri']};` : `${baseCspStr} ${allowedSources.join(' ')}`
|
||||
}
|
||||
|
||||
const policyObjectAvailable = typeof policies === 'object' && policies !== null && !Array.isArray(policies)
|
||||
|
||||
if (policyObjectAvailable) {
|
||||
const transformedPolicyObject = transformPolicyObject(policies, cspScriptSrcHashes)
|
||||
|
||||
return Object.entries(transformedPolicyObject).map(([k, v]) => `${k} ${v.join(' ')}`).join('; ')
|
||||
return Object.entries(transformedPolicyObject).map(([k, v]) => `${k} ${Array.isArray(v) ? v.join(' ') : v}`).join('; ')
|
||||
}
|
||||
|
||||
return baseCspStr
|
||||
|
@ -128,6 +128,26 @@ describe('basic ssr csp', () => {
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Contain report-uri in Content-Security-Policy-Report-Only header, when explicitly asked for CSRP, allowedSources, csp.report-url',
|
||||
async () => {
|
||||
const cspOption = {
|
||||
allowedSources: ['https://example.com', 'https://example.io'],
|
||||
reportOnly: true,
|
||||
policies: {
|
||||
'report-uri': '/csp_report_uri'
|
||||
}
|
||||
}
|
||||
nuxt = await startCspDevServer(cspOption)
|
||||
const { headers } = await rp(url('/stateless'))
|
||||
|
||||
expect(headers[reportOnlyHeader]).toMatch(/^script-src 'self' 'sha256-.*'/)
|
||||
expect(headers[reportOnlyHeader]).toContain('https://example.com')
|
||||
expect(headers[reportOnlyHeader]).toContain('https://example.io')
|
||||
expect(headers[reportOnlyHeader]).toContain('report-uri /csp_report_uri')
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Contain only unique hashes in header when csp.policies is set',
|
||||
async () => {
|
||||
@ -302,6 +322,26 @@ describe('basic ssr csp', () => {
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Contain report-uri in Content-Security-Policy-Report-Only header, when explicitly asked for CSRP, allowedSources, csp.report-url',
|
||||
async () => {
|
||||
const cspOption = {
|
||||
allowedSources: ['https://example.com', 'https://example.io'],
|
||||
reportOnly: true,
|
||||
policies: {
|
||||
'report-uri': '/csp_report_uri'
|
||||
}
|
||||
}
|
||||
nuxt = await startCspDevServer(cspOption)
|
||||
const { headers } = await rp(url('/stateless'))
|
||||
|
||||
expect(headers[reportOnlyHeader]).toMatch(/^script-src 'self' 'sha256-.*'/)
|
||||
expect(headers[reportOnlyHeader]).toContain('https://example.com')
|
||||
expect(headers[reportOnlyHeader]).toContain('https://example.io')
|
||||
expect(headers[reportOnlyHeader]).toContain('report-uri /csp_report_uri')
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Contain Content-Security-Policy-Report-Only header, when csp.policies.script-src is not set',
|
||||
async () => {
|
||||
|
Loading…
Reference in New Issue
Block a user