Как установить директивы CSP в NextJs с «строгой динамикой» и одноразовым номером или хэшем
Я потратил несколько часов, чтобы найти решение этой проблемы. Я думал, что если вы здесь, то вы точно знаете, о чем мы говорим, и не предложили эффективного решения. Если вам нужно узнать о директивах CSP, мы рекомендуем «погуглить!». Важно реализовать это в своих проектах.
Вам нужно отредактировать эти файлы: next.config.js и pages/_document.tsx
// next.config.js const crypto = require('crypto') onst nonce = crypto .createHash('sha256') .update(crypto.randomUUID()) .digest('base64') const isDev = process.env.NODE_ENV !== 'production' const ContentSecurityPolicy = ` base-uri 'self'; default-src 'self'; script-src 'self' 'nonce-${nonce}' 'strict-dynamic' https: 'unsafe-inline'${ isDev ? " 'unsafe-eval'" : '' }; child-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self' data:; connect-src 'self'; frame-src 'self'; img-src 'self'; ` module.exports = { env: { nonce, }, // Adding policies: async headers() { return [ { headers: [ { key: 'Content-Security-Policy', value: ContentSecurityPolicy.replace(/\s{2,}/g, ' ').trim(), }, ], }, ] }, } // pages/_document.tsx import { Html, Head, Main, NextScript } from 'next/document' import { cloneElement } from 'react' class CSPNextScript extends NextScript { getScripts(files) { return super .getScripts(files) .map((script) => cloneElement(script, { nonce: process.env.nonce })) } getPolyfillScripts() { return super .getPolyfillScripts() .map((script) => cloneElement(script, { nonce: process.env.nonce })) } getDynamicChunks(files) { return super .getDynamicChunks(files) .map((script) => cloneElement(script, { nonce: process.env.nonce })) } } class CSPHead extends Head { getScripts(files) { return super .getScripts(files) .map((script) => cloneElement(script, { nonce: process.env.nonce })) } getPolyfillScripts() { return super .getPolyfillScripts() .map((script) => cloneElement(script, { nonce: process.env.nonce })) } getDynamicChunks(files) { return super .getDynamicChunks(files) .map((script) => cloneElement(script, { nonce: process.env.nonce })) } } export default function Document() { return ( <Html lang="fr"> <CSPHead /> <body> <Main /> <CSPNextScript nonce={process.env.nonce} /> </body> </Html> ) }
Дополнительный тег scripts в вашем коде должен получить атрибут nonce так же, как мы сделали это для элемента CSPNextScript.
Готово!