使用Firebase时移除内容安全策略中script-src的unsafe-inline
在Next.js中为Firebase配置Nonce以移除CSP的'unsafe-inline'
1. 生成请求级别的随机Nonce
Nonce必须每个请求生成不同的值,所以要在服务器端处理:
- 用Next.js的Middleware生成Nonce,同时设置CSP头和自定义头传递Nonce到页面:
// middleware.ts import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; import crypto from 'crypto'; export function middleware(request: NextRequest) { // 生成16字节的base64格式nonce const nonce = crypto.randomBytes(16).toString('base64'); // 配置CSP,核心是script-src包含nonce和strict-dynamic const csp = ` default-src 'self'; script-src 'nonce-${nonce}' 'strict-dynamic'; style-src 'self' 'unsafe-inline'; connect-src 'self' *.firebaseio.com *.googleapis.com *.firebaseapp.com; img-src 'self' data:; font-src 'self'; frame-src 'self' *.firebaseapp.com; `.replace(/\s+/g, ' ').trim(); // 压缩空格避免格式问题 const response = NextResponse.next(); response.headers.set('Content-Security-Policy', csp); response.headers.set('X-Nonce', nonce); // 把nonce传给页面组件 return response; } export const config = { matcher: '/:path*', // 对所有路径生效 };
2. 在页面根布局中传递Nonce给Next.js
让Next.js的所有客户端脚本自动带上这个Nonce:
// app/layout.tsx(App Router) import { headers } from 'next/headers'; export default function RootLayout({ children }) { const nonce = headers().get('X-Nonce'); // 给html标签添加nonce属性,Next.js会自动给所有脚本加上nonce属性 return ( <html lang="zh-CN" nonce={nonce}> <body>{children}</body> </html> ); }
如果用Pages Router,就在_app.js里通过服务端方法获取并传递nonce:
// pages/_app.js function MyApp({ Component, pageProps }) { return ( <html nonce={pageProps.nonce}> <body> <Component {...pageProps} /> </body> </html> ); } // 在页面级别通过getServerSideProps生成并传递nonce export async function getServerSideProps(context) { const nonce = crypto.randomBytes(16).toString('base64'); const csp = ` default-src 'self'; script-src 'nonce-${nonce}' 'strict-dynamic'; style-src 'self' 'unsafe-inline'; connect-src 'self' *.firebaseio.com *.googleapis.com *.firebaseapp.com; `.replace(/\s+/g, ' ').trim(); context.res.setHeader('Content-Security-Policy', csp); return { props: { nonce } }; } export default MyApp;
3. 验证Firebase是否正常工作
- 彻底移除CSP中的
'unsafe-inline',启动应用测试Firebase Auth的登录流程(比如邮箱密码、第三方登录)和Firestore的数据读写。 - 如果遇到CSP报错,检查是否遗漏了必要的源:比如Firebase的API域名需要加入
connect-src,弹窗登录需要frame-src包含Firebase的域名。
关键说明
strict-dynamic是核心:它允许带有有效nonce的脚本加载其他脚本,不用手动列出所有脚本源,完美适配Firebase这类依赖多个动态加载脚本的包。- 不要重复生成Nonce:必须保证CSP头中的nonce和页面脚本中的nonce完全一致,否则脚本会被拦截。
内容的提问来源于stack exchange,提问作者Francesco
相关产品推荐
相关产品推荐

