NEXT.JS 16 · CH08 执行筛选器,不是授权边界

Proxy matcher 实验台

把一条请求放上检查轨:先看 source,再核对全部 has,最后确认每一项 missing。轨迹只回答“Proxy 是否执行”,不会替你回答“用户是否有权读取数据”。

命中 = sourceAND全部 hasAND全部 missing

请求装配台

编辑 pathname,切换规则,再装上 Cookie 或预取头。

可输入查询参数;source 在这里按解析后的 pathname 推演。

matcher 场景
请求携带的信号
Header next-router-prefetch: 1
当前规则忽略
Header purpose: prefetch
当前规则忽略

键盘:按 Ctrl/ + Enter 可重新推演;所有开关、场景和挑战均可用 Tab 操作。

逐层检查轨迹

只让工作区根路径及其后代进入 Proxy。

/workspace Cookie × router-prefetch × purpose ×
从左到右,短路检查 /workspace/:path*
  1. 通过

    source

    pathname 命中工作区根路径或其后代。

  2. 未配置

    has

    本场景没有 has 条件;这一层不阻断。

  3. 未配置

    missing

    本场景没有 missing 条件;这一层不阻断。

  4. 命中

    进入 Proxy

    所有已配置条件成立,Proxy 会执行;授权仍未完成。

当前 matcher 推演:进入 Proxy。这里只表示 Proxy 会运行,不代表授权已经通过。

跳过 Proxy ≠ 绕过授权

请求最终触达哪个服务端入口,哪个入口及其共享数据层就必须重新验证会话、租户关系和资源权限。

DAL集中验证数据访问
Route Handler接口入口自行授权
Server Action可被直接请求,重新授权
安全特例

_next/data 要单独理解

先看字面 matcher,再看框架的独立安全行为;不要把两件事揉成一个“万能正则结果”。

这个区别能避免两种误读:既不误称 negative lookahead 永远命中,也不依赖框架兜底代替数据入口授权。

本实验台的规则层

只按当前 source 字面推演

/_next/data/<build-id>/workspace.json

上方轨迹不会偷偷改写你的 negative lookahead,也不会假装复刻 Next.js 内部路由实现。

当前请求不是 _next/data;可载入下方“安全特例”挑战观察。
NEXT.JS 独立安全行为

显式排除后,Proxy 仍可能执行

即便 negative matcher 写了排除 _next/data,Next.js 仍可能让 Proxy 对对应数据请求执行,以减少“页面受保护、数据请求漏检查”的风险。这是框架的安全特殊处理,不是所有 negative lookahead 的普遍正则语义;应用仍须在 DAL、Route Handler 或 Server Action 完成权威授权。

规则刻度

读懂三层布尔条件

每一层都有自己的职责;上一层失败时,后续条件无需再决定结果。

matcher 应写成构建时可静态分析的字面量。不要用环境变量或运行时拼接去生成 config.matcher

source

从 pathname 开头匹配。/workspace/:path* 覆盖根路径和零个或多个后续路径段,不会命中 /blog/workspace

negative lookahead 适合缩小执行面,但排除项必须和 Proxy 的真实职责一起设计。

has

每一项都必须存在并满足指定值。本实验的 Cookie 只是一条 matcher 条件,不代表签名、会话或成员权限已经验证。

有 Cookie ≠ 已授权。Proxy 最多用它做快速、乐观的提前分流。

missing

  • 不写 value:该字段必须缺失。
  • 写了 value:字段缺失,或存在但值不匹配,都满足这一项。
  • 排除预取适合日志、分析等非安全副作用,不能用来放弃数据授权。
一键挑战

先载入,再预测

每张题卡会同时装好路径、场景与请求信号;你只需判断规则层的 Proxy 去向。

预测只针对 matcher 是否命中。无论答案是哪一个,下游权威授权都保持不变。

选择任意挑战后,再提交你的 matcher 预测。

尚未载入挑战。
配置抄写板

复制当前 matcher 片段

代码会随场景切换;请求信号只用于测试条件,不会被写进静态配置。

场景里的 matcher 只决定 Proxy 是否运行。它不验证 HTTP 方法、用户身份、租户关系或资源权限。

业务路径

匹配工作区根路径与任意深度后代。

export const config = {
  matcher: ['/workspace/:path*'],
}