关于 remix-v2-meta-sessions-review
用于审查 Remix v2 元数据、会话、身份验证门控和 CSRF 流程的技能。它提供检查清单与上下文相关规则,并对元数据格式和安全问题设置额外核验步骤。
主要功能
- 01元数据与 SEO 检查
- 02Cookie 和会话安全审查
- 03身份验证门控检查
- 04CSRF 保护检查
- 05发现问题前的核验门槛
适用场景
- 01审查元数据或根路由改动
- 02审计会话与 Cookie 配置
- 03检查身份验证和登出流程
- 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.mdcookie-security.mdcsrf.mdmeta-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附加令牌(不手动执行fetchPOST)
有效模式(不要标记)
以下用法是正确的 — 不要报告为问题:
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 |
硬性门槛(编写问题报告前)
请按顺序完成以下检查。在即将报告的问题批次通过所有门槛之前,不要起草面向用户的问题报告。
-
位置证据 — 通过: 每个问题都列出仓库路径,以及你读取的文件中的行范围或简短的逐字引文。仅依据差异或记忆提出的说法不通过。对于元数据/链接/会话问题,引用的文件必须是
.ts/.tsx路由模块、root.tsx或*.server.ts,不能是通用配置文件。 -
豁免检查 — 通过: 对于每个问题,你都能用一行说明它为何不属于 有效模式(不要标记) 的范围。特别是,必须明确排除
sameSite: "lax"、空的meta/links数组,以及标准的flash+commitSession两行模式。 -
Meta 结构检查 — 通过: 在标记任何与
meta有关的问题之前,你已阅读实际的函数体并确认其返回内容。TypeScript 可能会掩盖实际结构(v1 对象可能满足类型不严谨的MetaFunction别名)。检查方法:返回表达式以[开头,且每个元素都是描述符对象。如果以{开头,就是 v1 结构——标记为严重问题。如果是[],则有效(不要标记)。 -
协议 — 通过: 你已为此次审查完成 审查验证协议 中的提交前验证清单。
何时加载参考资料
- 审查任何
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
审查问题
- 每个
meta导出是否都返回数组?每个 OG/Twitter 标签是否都是{ property, content }? root.tsx是否在<head>内包含<Meta />和<Links />?- Cookie 是否设置了
httpOnly和secure: NODE_ENV === 'production',且secrets来自环境变量并存放在数组中(以支持密钥轮换)? - 每次修改会话后,是否都通过
Set-Cookie: await commitSession(session)标头提交? - 身份验证是否通过会抛出异常的辅助函数在 loader/action 中进行门控,而不是在组件中?
- 注销是否通过
action(POST)实现?修改数据的 action 是否会验证 CSRF(或说明威胁模型)?
补充文档
- references/meta-v2-shape.md — v2 代码库中的 v1 对象结构(重大变更)、OG 简写、
document.title反模式、根目录脚手架、父级合并 - references/cookie-security.md —
httpOnly/secure/sameSite、硬编码密钥、密钥轮换规范 - references/auth-gates.md — loader 级门控、注销必须使用 action、提交配对、flash 模式
- references/csrf.md —
remix-utils/csrf接线、手动 fetch 绕过、专用 Cookie、共享密钥规范