You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 15:27:52