diff --git a/__tests__/pages/_document.test.js b/__tests__/pages/_document.test.js index 1689baae1..2c9de0bb7 100644 --- a/__tests__/pages/_document.test.js +++ b/__tests__/pages/_document.test.js @@ -1,9 +1,19 @@ import '@testing-library/jest-dom' import MyDocument from '../../pages/_document' +//mocks +jest.mock('../../lib/Utils', () => ({ + generateNonce: jest.fn().mockReturnValue('test'), +})) + describe('_document', () => { it('returns initialProps', async () => { - const props = { html: 'html', head: 'head', styles: 'styles' } + const props = { + html: 'html', + head: 'head', + styles: 'styles', + nonce: 'test', + } const result = await MyDocument.getInitialProps({ defaultGetInitialProps: async (docCtx, options = {}) => { return props @@ -13,7 +23,7 @@ describe('_document', () => { }) it('renders', () => { - const sut = new MyDocument() + const sut = new MyDocument({ nonce: 'test' }) const result = sut.render() expect(result).toBeTruthy() }) diff --git a/lib/Utils.js b/lib/Utils.js index d2c1ffec2..1e81d5a53 100644 --- a/lib/Utils.js +++ b/lib/Utils.js @@ -1,3 +1,5 @@ +import crypto from 'crypto' + export function formatDate(value, locale) { const options = { year: 'numeric', month: 'long', day: 'numeric' } let date @@ -39,3 +41,7 @@ export function getGreeting(time) { return 'greeting' } } + +export function generateNonce() { + return crypto.randomBytes(16).toString('base64') +} diff --git a/next.config.js b/next.config.js index 73c27d12d..4133f3521 100644 --- a/next.config.js +++ b/next.config.js @@ -31,14 +31,15 @@ const securityHeaders = [ key: 'Referrer-Policy', value: 'same-origin', }, - { - key: 'Content-Security-Policy', - value: `frame-ancestors 'self'`, - }, { key: 'X-Frame-Options', value: 'SAMEORIGIN', }, + { + key: 'Content-Security-Policy', + value: + "base-uri 'self';form-action 'self';default-src 'self';style-src 'self' https://fonts.googleapis.com 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' https://fonts.gstatic.com data:;frame-ancestors 'self';", + }, ] const config = { diff --git a/pages/_document.js b/pages/_document.js index 2e52d2cd6..56fca470f 100644 --- a/pages/_document.js +++ b/pages/_document.js @@ -1,27 +1,41 @@ import Document, { Html, Head, Main, NextScript } from 'next/document' +import { generateNonce } from '../lib/Utils' import Script from 'next/script' class MyDocument extends Document { static async getInitialProps(ctx) { + const nonce = generateNonce() const initialProps = await Document.getInitialProps(ctx) - return { ...initialProps } + + if (ctx.res) { + //append dynamic headers + let csp = ctx.res.getHeader('Content-Security-Policy') + csp += `script-src 'self' 'nonce-${nonce}' 'unsafe-eval';` + ctx.res.setHeader('Content-Security-Policy', csp) + } + + return { ...initialProps, nonce } } render() { + const { nonce } = this.props return ( -
+ -