按框架
Next.js 安全 — 生产环境加固实务参考
一份 Next.js 生产环境加固实务参考:按优先级排序的检查清单,外加服务端/客户端边界与环境变量、依赖 CVE、Server Actions 授权、SSRF、响应头/CSP、速率限制等各领域指南,并附一份自我验证清单。纯防御视角,不含任何攻击步骤。适合正在运营 Next.js 应用、想把生产环境真正加固到位的人从头到尾照着做。
适合对象:任何运营 Next.js 应用(假设使用 App Router)的人。这里不含攻击步骤——这是一份用于加固的可上手实务参考:按优先级排序的检查清单、分领域指南和自我验证。跨框架的整体图景,见 按框架分类的安全入口。
按优先级排序的加固检查清单
从上往下逐条落实这张表。P0 是前提,P1 是最高频的事故来源,P2 是持续的运维卫生。
P0 ── 前提(先做这个)
密钥只留服务端 / 依赖 CVE 监控 + 快速打补丁 / 夯实生产配置
P1 ── 最高频的事故来源
Server Actions/Route Handlers 授权 + 输入校验 / 服务端 fetch 的 SSRF
P2 ── 运维卫生
响应头/CSP / 认证、会话、Cookie / 速率限制
| 优先级 | 控制项 | 具体做法(Next.js) |
|---|---|---|
| P0 | 密钥只留服务端 | NEXT_PUBLIC_ 只用于浏览器可安全暴露的值;密钥只在 Server Component/Action/Route Handler 内 |
| P0 | 依赖 CVE | 用 npm audit/osv-scanner 监控;按实际运行版本判定,快速打补丁。跟进核心 RCE |
| P0 | 生产配置 | 跑生产构建;出错时别泄露内部信息(stack/env) |
| P1 | Action 授权 | 每个 Server Action/Route Handler 都做认证 + 按所有者划分范围的授权 |
| P1 | 输入校验 | 对输入做 schema 校验(类型/范围/允许值)。别信任客户端 |
| P1 | SSRF 防护 | 把服务端 URL 抓取限制到白名单 + 阻断内网 IP/元数据。收紧图片远程 pattern |
| P2 | 响应头/CSP | 在 next.config 中配置安全响应头 + HSTS。App Router 上考虑基于 nonce 的 CSP |
| P2 | 认证/Cookie | 会话 Cookie 设 Secure/HttpOnly/SameSite。别把授权只交给中间件 |
| P2 | 速率限制 | 对认证、Server Actions 和 Route Handlers 施加限制 |
1. 服务端/客户端边界与环境变量(P0)
Next.js 最大的事故来源,是本应只留在服务端的密钥最终跑到了客户端。
- 只给浏览器可安全暴露的值加
NEXT_PUBLIC_前缀。 绝不加在 API 密钥或连接信息上(NEXT_PUBLIC_的值会在构建时被打进客户端 bundle,访问者可见)。 - 只在 Server Components / Server Actions / Route Handlers 内部读取密钥,并让它们远离
props和响应(被序列化的值)。 - 让服务端专用模块不被客户端 import(意外引入可能把密钥一并打包)。见 .env 文件与密钥。
2. 依赖 CVE 与核心(P0)
- 用
npm audit或 osv-scanner 机器监控依赖(npm)CVE,按实际运行版本判定,并快速打补丁(依据真正装上的东西来决策,而非 package.json 里的声明)。 - Next.js 核心出现过严重的 RCE,所以一旦公开就要快速跟进。运维层面的做法见 别在 CVE 上掉队;实操见 漏洞响应实操手册。
- 让 Node/Next 保持在受支持的版本上,别把已到 EOL 的版本一直摆着不管。
3. Server Actions / Route Handlers(授权 + 校验,P1)
它们是公开的服务端入口。 能被调用不等于允许执行。
常见(危险)
- 把 action 当成「登录了就允许」
- 只依赖中间件的认证,没有所有者检查
- 未经校验就把输入送进数据库或外部调用
- 原样信任客户端提供的值(ID、标志位)
正确
- 在每个 action/handler 里,认证之外再加按所有者/权限划分范围的授权
- 别只交给中间件(在离数据近的地方做授权)
- 对输入做 schema 校验(类型/范围/允许值)
- 在服务端重新校验,让 ID 替换不起作用
见 什么是 IDOR。在每一条读取/更新/删除路径上都做所有者检查。
4. SSRF 与服务端抓取(P1)
在服务端抓取用户提供的 URL(图片代理、webhook、元数据抓取)是 SSRF 的入口。
- 把目标限制到白名单,并在建立连接时阻断触及内网 IP 和云元数据(169.254.169.254)。
- 把图片优化的远程 pattern 保持到最少(别允许抓取任意主机)。
- 见 什么是 SSRF。本站的出站抓取都走一个 SSRF 安全网关。
5. 注入与输出
- XSS:React 默认会转义输出。别把用户输入传给
dangerouslySetInnerHTML(确有必要时也只在净化之后)。见 什么是 XSS。 - SQL/注入:用 ORM/占位符做绑定;绝不用字符串拼接来构造查询(→ 什么是 SQL 注入)。
- 别把外部输入传给
eval之类危险的求值。
6. 安全响应头与 CSP(P2)
- 在
next.config中设置安全响应头(X-Content-Type-Options 等)和 HSTS。用 安全响应头检测 检查你自己的站点。 - 在 App Router 上,考虑基于 nonce 的 CSP(避免一揽子允许内联脚本)。注意与分析/广告标签共存需要一番设计。
7. 认证、会话、Cookie(P2)
- 在会话 Cookie 上设置 Secure / HttpOnly / SameSite。
- 别把授权只委托给中间件的认证——中间件只是补充;在 action/handler/数据层里核验真正的决策(有些路径可能绕过中间件)。
- 登录时恰当地重新生成并失效会话。
8. 速率限制(P2)
- 对认证、Server Actions 和 Route Handlers 施加尝试次数/吞吐量限制,以遏制暴力破解、滥用和 DoS。
验证:你的 Next.js 真的加固了吗?
搭好了并不算完——只有检查过才算完成。以下是针对你自己站点/环境的防御性自查。
没有密钥泄露给客户端
NEXT_PUBLIC_ 前缀。生产环境出错时不泄露内部信息
Action 授权站得住
响应头、依赖、SSRF
npm audit/osv 干净,且出站抓取无法触及内网 IP。本站观点:管理的是「边界与依赖」,不是核心
本站就跑在 Next.js 上,防守的重心不在花哨的配置,而在服务端/客户端的边界与依赖的新鲜度。 密钥只留在服务端,公开入口(Server Actions/Route Handlers)一律带授权和输入校验,依赖在每次部署前都做一次 CVE 审计。本站自身的出身就是一起「未打补丁的 CVE 被自动利用」的事故,所以机器监控依赖是最优先的习惯。出站的 URL 抓取都走一个 SSRF 安全网关,让它无法触及内网 IP 或元数据。
延伸阅读
- 入口:按框架分类的安全 · Laravel 安全
- 依赖:别在 CVE 上掉队 · 漏洞响应实操手册
- 术语:什么是 IDOR · 什么是 SSRF · .env 文件与密钥 · XSS
- 工具:安全响应头检测
FAQ
Q要保护 Next.js,我应该先做什么?
三件 P0 事项:(1) 让密钥只留在服务端(只给浏览器可安全暴露的值加 NEXT_PUBLIC_ 前缀,绝不给 API 密钥或连接信息加);(2) 用机器监控依赖 CVE,按实际运行版本判定,并快速打补丁(含核心 RCE);(3) 夯实生产环境配置(跑生产构建;出错时别泄露内部信息)。接下来再转向 Server Actions / Route Handlers 的授权与输入校验,以及 SSRF 防护。
Q环境变量该怎样安全处理?
原则是「密钥只留在服务端」。只给浏览器可安全暴露的值加 NEXT_PUBLIC_ 前缀,绝不加在 API 密钥或连接信息上(NEXT_PUBLIC_ 的值会在构建时被打进客户端 bundle,访问者可见)。只在 Server Component / Server Actions / Route Handlers 内部读取密钥,并从设计上确保它们绝不会漏进 props 或响应。
Q使用 Server Actions 时该注意什么?
Server Actions 和 Route Handlers 是公开的服务端入口。能被调用不等于允许执行。在登录(认证)之上,要写授权,把每个操作限定到拥有该资源的用户,并始终校验输入(例如 schema 校验)。别只依赖中间件的认证——也要在 action/handler 里做所有者检查。
Q如何为 SSRF 做准备?
主要入口是在服务端抓取用户提供的 URL(图片代理、webhook、元数据抓取)。把目标限制到白名单,并在建立连接时阻断触及内网 IP 和云元数据(169.254.169.254)。把图片优化的远程 pattern 保持到最少。细节见术语页。
Q如何管理 npm 依赖漏洞?
用 npm audit 或 osv-scanner 机器监控已知 CVE,按实际运行版本判定,并快速打补丁(依据真正装上的东西来决策,而非 package.json 里的声明)。Next.js 核心出现过严重的 RCE,所以快速跟进很重要。同时让 Node/Next 保持在受支持的版本上,别把已到 EOL 的版本一直摆着不管。