英文:
How to add nonce to inline styles and scripts in Next.js?
问题
假设存在以下 Content-Security-Policy
策略:
default-src 'self'; script-src https://ray.run
由于以下错误,Next.js 无法正常运行:
> 拒绝应用内联样式,因为它违反了以下内容安全策略指令:"default-src 'self'"。要启用内联执行,需要使用"unsafe-inline"关键字、哈希('sha256-zu3j41gcw4FOWZYIiUz/VyL9HYakAfKLQFMCEcWNkAc=')或一个随机数('nonce-... ')注意,哈希不适用于事件处理程序、样式属性和JavaScript导航,除非存在"unsafe-hashes"关键字。还请注意,未明确设置"style-src",因此将使用"default-src"作为后备。
>
> 拒绝执行内联脚本,因为它违反了以下内容安全策略指令:"script-src https://ray.run"。要启用内联执行,需要使用"unsafe-inline"关键字、哈希('sha256-qJ8ozvdSL8lvQo3N0L0SYjL5lY0bLZcaD/xXL4BlEpQ=')或一个随机数('nonce-... ')。
根据错误提醒,我有两个选项:允许 "unsafe-inline" 或添加 nonce
。然而,在阅读 Next.js 文档时,我无法找到如何将 nonce
添加到内联样式和脚本中的任何提及。
为了提供背景信息,我正在使用带有 React Server Component (RSC) 的 Next.js 版本13。
英文:
Assuming Content-Security-Policy
policy such as:
default-src 'self'; script-src https://ray.run
Next.js fails to function because of errors such as:
> Refused to apply inline style because it violates the following Content Security Policy directive: "default-src 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-zu3j41gcw4FOWZYIiUz/VyL9HYakAfKLQFMCEcWNkAc='), or a nonce ('nonce-...') is required to enable inline execution. Note that hashes do not apply to event handlers, style attributes and javascript: navigations unless the 'unsafe-hashes' keyword is present. Note also that 'style-src' was not explicitly set, so 'default-src' is used as a fallback.
>
> Refused to execute inline script because it violates the following Content Security Policy directive: "script-src https://ray.run". Either the 'unsafe-inline' keyword, a hash ('sha256-qJ8ozvdSL8lvQo3N0L0SYjL5lY0bLZcaD/xXL4BlEpQ='), or a nonce ('nonce-...') is required to enable inline execution.
As per what the error suggests, I have two options: allow "unsafe-inline" or add nonce
. However, reading Next.js documentation I cannot find any mention of how to nonce
to the inlined styles and scripts.
For context, I am using [tag:next.js13] with React Server Component (RSC).
答案1
得分: 4
要向<script>
和<styles>
标签添加nonce
属性,您需要在middleware.ts
文件中定义content-security-policy
头部(适用于next@13.4.0
及更高版本)。
Next.js会解析该头部(在renderToHTMLOrFlight
函数中)以提取nonce
值,然后将其添加到生成的HTML标签中。
以下是middleware
函数的示例:
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const nonce = crypto.randomUUID();
const csp = `script-src 'nonce-${nonce}';`;
// 克隆请求头部
const requestHeaders = new Headers(request.headers);
// 设置CSP头部,以便Next.js可以读取它并生成带有nonce的标签
requestHeaders.set('content-security-policy', csp);
// 创建新的响应
const response = NextResponse.next({
request: {
// 新的请求头部
headers: requestHeaders
}
});
// 也在响应中设置CSP头部,以便输出到浏览器
response.headers.set('content-security-policy', csp);
return response;
}
如果需要,您还可以添加一个自定义请求头来读取页面中的nonce
值:
requestHeaders.set('x-nonce', nonce);
根据mdn文档的说明:
Nonces应该在每次页面加载时以不同的方式生成(只生成一次nonce!)。
这意味着您不能在next.config.js
文件中设置它,因为它只会在构建时生成一次。在middleware
函数中,nonce
值将在每个请求中重新生成。
最后但并非最不重要的,这仅适用于动态路由,而不适用于静态渲染,因为nonce
值必须在每次页面加载时不同。
代码最初由@danieltott在GitHub上发布:https://github.com/vercel/next.js/issues/43743#issuecomment-1542684019
相关讨论:
- https://github.com/vercel/next.js/discussions/43710
- https://github.com/vercel/next.js/discussions/49648
英文:
To add the nonce
attribute to <script>
and <styles>
tags, you need to define the content-security-policy
header in the middleware.ts
file (works with next@13.4.0
and higher).
The header is parsed by Next.js (in the renderToHTMLOrFlight
function) to extract the nonce
value, which is then added to the generated HTML tags.
Here's an example of the middleware
function:
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const nonce = crypto.randomUUID();
const csp = `script-src 'nonce-${nonce}';`;
// Clone the request headers
const requestHeaders = new Headers(request.headers);
// Set the CSP header so that Next.js can read it and generate tags with the nonce
requestHeaders.set('content-security-policy', csp);
// Create new response
const response = NextResponse.next({
request: {
// New request headers
headers: requestHeaders
}
});
// Also set the CSP header in the response so that it is outputted to the browser
response.headers.set('content-security-policy', csp);
return response;
}
If necessary, you can also add a custom request header to read the nonce
value in your pages:
requestHeaders.set('x-nonce', nonce);
To go further, according to the mdn documentation:
> Nonces should be generated differently each time the page loads (nonce only once!).
This means you can't set it in the next.config.js
file, as it will only be generated once at build time. In the middleware
function, the nonce
value will be regenerated for each request.
Last but not least, this only works with dynamic routes and not with static rendering, since the nonce
value must be different for each page load.
Code originaly published by @danieltott on GitHub: https://github.com/vercel/next.js/issues/43743#issuecomment-1542684019
Related discussions:
答案2
得分: 0
只是额外信息,如果您添加了一次性随机数并生成了一份灯塔报告,它仍然会抱怨:“考虑添加'unsafe-inline'(被支持nonce/hashes的浏览器忽略)以向较旧的浏览器兼容”,这个问题的严重性被标记为中等。在我的情况下,我同时添加了随机数和unsafe-inline。
英文:
Just an additional info, If you add nonce and generate a lighthouse report it will still complain: "Consider adding 'unsafe-inline' (ignored by browsers supporting nonces/hashes) to be backward compatible with older browsers.", and the severity for this one is labeled as Medium. In my case, I added both the nonce and the unsafe-inline.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论