FlawOpen

flawopen.com/参考/Next.js Server Actions CSRF

Next.js Server Actions 的 CSRF:Origin 检查与安全配置

CWE-352: Cross-Site Request Forgery (CSRF)框架安全指南
简要回答

Next.js Server Actions 使用 POST,并将 Origin 的主机与 x-forwarded-host 或 host 比较。这类似于确认访客邀请上的地点与服务器预期地点一致。该检查有助于阻止跨站提交,但不代表授权:每个操作仍须验证用户身份、输入和权限。

有一项重要限制:当前 Next.js 文档说明,没有 Origin 的请求会带警告继续处理。反向代理也会影响比较所用的主机。应把这项检查视为一层防护,并让代理建立可信主机值。

Origin
浏览器提供的发起页面来源;Next.js 将其主机与应用主机比较。
Host / X-Forwarded-Host
Next.js 用于比较的主机值。代理必须设置或验证转发信息。
allowedOrigins
Server Actions 可接受的额外 Origin 主机清单。Next.js 支持精确主机和通配符模式。
Authorization
针对每个操作判断已认证用户是否可以对这个特定对象执行该操作。

Server Actions 内置 CSRF 检查的工作方式

1

浏览器提交 Server Action

Server Action 通过 HTTP POST 调用。SameSite cookie 默认可阻止许多跨站提交,但仅靠 POST 并非完整的 CSRF 防护。

2

Next.js 比较主机值

存在 Origin 时,Next.js 会将其主机与 x-forwarded-host 或 host 比较。若不匹配且未列入 serverActions.allowedOrigins,请求会被拒绝。

3

操作仍须执行自身策略

请求检查后,操作必须验证用户身份、校验每个参数并授权该操作。操作 ID 和隐藏表单字段不能充当访问控制。

重要限制:缺少 Origin 与 allowedOrigins

文档说明的默认行为不会拒绝缺少 Origin 的请求

当前文档指出,没有 Origin 的请求会带警告继续处理。不要假定每个请求都通过了 Origin 比较。应调查缺失原因,并始终在操作内部验证身份、授权和输入。

通配符会扩大可信来源范围

allowedOrigins 接受精确主机和通配符:* 匹配一个标签,** 匹配一个或多个。只允许组织控制且确有需要的域名和子域。若通配符覆盖用户可控子域,就可能信任组织无法控制的来源。

将反向代理作为安全边界的一部分配置

Next.js 使用 x-forwarded-host 或 host 进行比较。边缘代理应丢弃客户端提供的转发头,并根据已验证的公网主机设置该值;应用只能通过可信代理访问。若代理转发其内部主机名,只在 allowedOrigins 中配置所需公网来源。不要通过信任任意主机来消除不匹配。

信任范围过宽
// Every subdomain, including delegated or tenant-controlled names, is trusted.
module.exports = {
  experimental: {
    serverActions: {
      allowedOrigins: ['**.example.com'],
    },
  },
};
信任范围收窄
// Add only the public host that this deployment requires.
module.exports = {
  experimental: {
    serverActions: {
      allowedOrigins: ['admin.example.com'],
    },
  },
};

// Configure the edge to overwrite X-Forwarded-Host
// with the validated public hostname.

Host 公告:相关风险,但与 CSRF 不同

对 Host 的信任曾导致 Server Actions 中已披露的 SSRF 问题。CVE-2024-34351 影响 14.1.1 之前的自托管版本,条件是操作执行以 / 开头的相对重定向且 Host 可被更改。另一个 Vercel 2026 年 7 月公告描述了自定义服务器允许客户端控制主机相关请求头时的 SSRF 和内部值泄露风险,修复版本列为 15.5.21 与 16.2.11。这些是主机信任问题,不能证明 Origin CSRF 检查本身可被绕过。

针对 2026 年公告,应升级到修复版本。升级前,在边缘或代理处固定或验证 Host 和 X-Forwarded-Host。公告还记录了 14.2.0 及更高版本可额外使用 __NEXT_PRIVATE_ORIGIN。采用该措施前,应以公告核对受影响和受支持的版本分支。

为每个 Server Action 执行授权和校验

Next.js 文档要求将 Server Action 参数视为不可信数据,并检查当前用户是否有权调用操作。易受攻击的示例信任客户端提供的对象 ID。修复模式会验证身份、校验 ID,并在数据库变更本身加入所有权条件。

缺少对象授权
"use server";

export async function deleteInvoice(invoiceId: string) {
  await db.invoice.delete({ where: { id: invoiceId } });
}
验证身份、输入与权限
"use server";

import { z } from "zod";
import { requireUser } from "@/auth";

const invoiceIdSchema = z.string().uuid();

export async function deleteInvoice(rawId: unknown) {
  const user = await requireUser();
  const invoiceId = invoiceIdSchema.parse(rawId);
  const result = await db.invoice.deleteMany({
    where: { id: invoiceId, ownerId: user.id },
  });
  if (result.count !== 1) throw new Error("Forbidden");
}

Server Actions 的 CSRF 与授权检查清单

参考资料

另请参阅 跨站请求伪造(CSRF,CWE-352):原理与防御方法 — flawopen.com SameSite=Strict 能取代 CSRF 令牌吗? GET 请求需要 CSRF 令牌吗? localStorage 中的 JWT 与 HttpOnly Cookie:哪个更安全? — flawopen.com