mcpField
R
remix-v2-meta-sessions-review

remix-v2-meta-sessions-review

github.com/existential-birds测试与质量8541 次安装11 周前更新
代码仓库

关于 remix-v2-meta-sessions-review

用于审查 Remix v2 元数据、会话、身份验证门控和 CSRF 流程的技能。它提供检查清单与上下文相关规则,并对元数据格式和安全问题设置额外核验步骤。

主要功能

  1. 01元数据与 SEO 检查
  2. 02Cookie 和会话安全审查
  3. 03身份验证门控检查
  4. 04CSRF 保护检查
  5. 05发现问题前的核验门槛

适用场景

  1. 01审查元数据或根路由改动
  2. 02审计会话与 Cookie 配置
  3. 03检查身份验证和登出流程
  4. 04审查变更操作中的 CSRF 处理

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/existential-birds/beagle --skill remix-v2-meta-sessions-review

安装后在 Claude Code 中输入/remix-v2-meta-sessions-review确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
auth-gates.md
cookie-security.md
csrf.md
meta-v2-shape.md

详细介绍

Remix v2 Meta、会话、身份验证和 CSRF 代码审查

审查 Remix v2 的 meta/SEO、会话、身份验证门控和 CSRF 代码路径。当差异涉及以下任一内容时,由总控 review-remix-v2 审查器加载: meta/links 导出、root.tsx、*.server.ts 会话/ Cookie 模块、读取或写入 session 的加载器/操作函数,或 <Form>/useFetcher 变更。

参见 remix-v2-meta-sessions 获取规范模式。

快速参考

问题类型参考资料
meta 返回 v1 对象形状(重大变更)、OG 简写、在 effect 中使用 document.title、缺少 <Meta />/<Links />、父级合并references/meta-v2-shape.md
缺少 httpOnly/secure、硬编码密钥、单字符串 secrets、轮换时替换而非前置references/cookie-security.md
在组件中检查身份验证、在加载器中注销、缺少 commitSession、flash 后未提交references/auth-gates.md
手动 fetch POST 绕过 CSRF、令牌存于会话 Cookie 中、没有 CSRF 保护、共享密钥references/csrf.md

最高优先级检测——首先指出: 在 v2 代码库中使用 v1 meta 对象形状(return { title, description })。这能通过类型检查,但运行时会忽略它,页面渲染时没有标题和 meta 标签。搜索每个 export const meta,并确认返回值以 [ 开头,而不是 {。

审查清单

  • meta 返回 MetaDescriptor[](数组以 [ 开头),而非 v1 对象形状
  • OG / Twitter 标签使用 { property, content },而非 v1 简写 { "og:title": "..." }
  • 不使用 document.title = "..." 或 useEffect(() => { document.title = ... })——meta 通过 meta 导出设置
  • root.tsx 在 <head> 中包含 <Meta /> 和 <Links />
  • 需要父级值的子级 meta 使用 matches.flatMap((m) => m.meta ?? [])
  • meta 对 data 进行空值保护(加载器可能尚未运行,或在 404 时返回 undefined)
  • Cookie 配置设置 httpOnly: true 和 secure: process.env.NODE_ENV === "production"
  • secrets 从 process.env 读取(没有硬编码字符串,也没有提交 .env.example 中的值)
  • secrets 是支持轮换的数组(将新密钥前置,保留旧密钥),而非单个值
  • 每次 session.set/session.unset/session.flash 后,都要返回带有 "Set-Cookie": await commitSession(session) 的响应
  • 身份验证门控通过 requireUserId(request) 放在 loader(或 action)中,而非在组件级重定向
  • 注销使用 action(POST),而非 loader(GET)
  • 使用 CSRF 保护时,变更操作会调用 csrf.validate(request)
  • CSRF 令牌使用专用的 createCookie("csrf", ...),而非会话 Cookie
  • 变更操作使用 <Form> / useFetcher,以便 AuthenticityTokenInput 附加令牌(不手动执行 fetch POST)

有效模式(不要标记)

以下用法是正确的 — 不要报告为问题:

  • sameSite: "lax" — 可接受的默认值。并非每个应用都需要 "strict";只有在威胁模型要求更严格的设置时才标记(例如,未以其他方式提供 CSRF 保护)。
  • meta 返回 [] — 当路由有意不输出任何 meta(继承根路由标签或依赖同级路由)时,这是合理的。
  • links 返回 [] — 当路由没有专属样式表或预加载项时,这是合理的。
  • session.flash(...) 后在下一行调用 commitSession(session) — 标准的两行 flash 模式。分开写是正确的;不要将其标记为“缺少 commit”。
  • 在 action(而非 loader)中进行身份验证检查 — 对于仅限 POST 的路由(例如 logout、delete)是正确的。Loader 控制 GET 请求;action 控制变更操作。
  • 在 root.tsx 的 <head> 中使用普通 JSX <meta> 声明 charset 和 viewport — 相比 meta 导出,这是更好的做法,可避免 v2 不合并行为导致的重复标签警告。
  • secrets: [process.env.X!, process.env.X_OLD!] — 当上方存在快速失败保护(if (!process.env.X) throw)时,! 非空断言可以接受。
  • 在 loader/action 内使用 throw redirect(...) — 这是 Remix 的规范模式;有意抛出该响应。
  • 在 loader 中调用 commitSession(而不只是 action) — 当 loader 读取 flash 消息并必须将其清除时,这是必需的。

上下文相关规则

只有在符合特定上下文时才标记以下问题:

问题仅在以下情况下标记
action 中缺少 CSRF 验证应用声明将 remix-utils/csrf 作为其保护机制,或者该 action 面向公众(非内部/VPN 限制访问)且不存在 Origin 检查
sameSite: "lax"应用没有基于库的 CSRF 保护,且没有 Origin 检查 — 此时 "lax" 成为唯一防护措施,且不足以提供保护
缺少 secure 标志Cookie 配置是生产环境中的会话/CSRF Cookie(而非测试样例或注释示例)
meta 返回 []文档说明该路由需要专属标签(例如公共落地页)— 空数组通常表示有意继承,默认不要标记
在 action 而非 loader 中进行身份验证检查路由可通过 GET 渲染(具有 loader)— 对于仅限 POST 的路由,action 才是正确的控制点
在 action 中执行 Logout 且使用 <Form method="post">绝不要标记 — 这是规范模式
手动 fetch POST目标是内部 Remix action,且未通过请求头附加 CSRF 令牌
secrets: [singleValue]应用处于生产环境,或者已部署足够长的时间,需要进行轮换 — 将其标记为建议,而非 CRITICAL

硬性门槛(编写问题报告前)

请按顺序完成以下检查。在即将报告的问题批次通过所有门槛之前,不要起草面向用户的问题报告。

  1. 位置证据 — 通过: 每个问题都列出仓库路径,以及你读取的文件中的行范围或简短的逐字引文。仅依据差异或记忆提出的说法不通过。对于元数据/链接/会话问题,引用的文件必须是 .ts/.tsx 路由模块、root.tsx 或 *.server.ts,不能是通用配置文件。

  2. 豁免检查 — 通过: 对于每个问题,你都能用一行说明它为何不属于 有效模式(不要标记) 的范围。特别是,必须明确排除 sameSite: "lax"、空的 meta/links 数组,以及标准的 flash + commitSession 两行模式。

  3. Meta 结构检查 — 通过: 在标记任何与 meta 有关的问题之前,你已阅读实际的函数体并确认其返回内容。TypeScript 可能会掩盖实际结构(v1 对象可能满足类型不严谨的 MetaFunction 别名)。检查方法:返回表达式以 [ 开头,且每个元素都是描述符对象。如果以 { 开头,就是 v1 结构——标记为严重问题。如果是 [],则有效(不要标记)。

  4. 协议 — 通过: 你已为此次审查完成 审查验证协议 中的提交前验证清单。

何时加载参考资料

  • 审查任何 export const meta 或 export const links,或审查 root.tsx 时 → meta-v2-shape.md
  • 审查 createCookieSessionStorage、createCookie,或任何配置 Cookie 的 *.server.ts 时 → cookie-security.md
  • 审查读取或写入 session 的 loader/action,或任何身份验证辅助函数时 → auth-gates.md
  • 审查表单、fetcher 或任何会修改数据的路由时 → csrf.md

审查问题

  1. 每个 meta 导出是否都返回数组?每个 OG/Twitter 标签是否都是 { property, content }?
  2. root.tsx 是否在 <head> 内包含 <Meta /> 和 <Links />?
  3. Cookie 是否设置了 httpOnly 和 secure: NODE_ENV === 'production',且 secrets 来自环境变量并存放在数组中(以支持密钥轮换)?
  4. 每次修改会话后,是否都通过 Set-Cookie: await commitSession(session) 标头提交?
  5. 身份验证是否通过会抛出异常的辅助函数在 loader/action 中进行门控,而不是在组件中?
  6. 注销是否通过 action(POST)实现?修改数据的 action 是否会验证 CSRF(或说明威胁模型)?

补充文档

提交问题报告前

完成硬性门槛(尤其是第 3 项——Meta 结构检查),然后只报告仍通过审查验证协议提交前检查的问题。

评论

支持 Markdown