JWT Cookie、token_version 与账户征用规则:freehire 如何防住账户接管
发布时间:2026/10/22 2:28:13 锦皓数字建站

【免费下载链接】freehirefreehire — the open-source search engine for job seekers项目地址https://gitcode.com/GitHub_Trending/fr/freehire点击查看免费下载freehire是一个开源的 IT 岗位搜索引擎它直连公司 ATS 抓取 330 万 条一手职位。账号安全是它容易被忽视却最关键的基建本文拆解 freehire 如何用JWT Cookie传输会话、用token_version让无状态令牌可被撤销以及一套名为账户征用seizure的规则如何彻底防住抢注邮箱 → 接管账户这条最经典的攻击链。一、会话为什么放在 JWT Cookie 里而不是 localStorage很多前端项目把 JWT 存在localStorage里再手动塞进Authorization: Bearer请求头——代价是任何 XSS 脚本都能直接读走令牌。freehire 的选择是反过来的令牌只存在于hire_tokenCookie 中属性为HttpOnly; SameSiteLaxHTTPS 部署下再叠加Secure。JavaScript 根本读不到它XSS 无法窃取SameSiteLax又让跨站请求默认不带 Cookie免掉了 CSRF Token 的负担SPA 和 API强制同源开发环境由 Vite 代理转发/api令牌本身是HS256 签名的 JWT载荷里只有三样东西用户 idsub、一次随机会话 idjti、以及本文的主角tvtoken 版本号签名密钥JWT_SECRET是启动即校验的必填项缺失直接拒绝启动fail-fast。也就是说浏览器登录态完全由服务端掌控前端既不能读、也不能伪造。 相关实现cookie.go、token.go二、token_version给无状态 JWT装上撤销开关无状态 JWT 的天然短板是签出去就收不回来。过期之前它一直有效改密码、登出别处都管不到它。freehire 的解法是一列数据库字段users.token_version账号初始值为1签发时盖章每次登录新令牌都会把当前token_version写进tv声明每次请求比对认证中间件解析令牌后用其中的用户 id 查库拿最新版本号tv不一致立刻返回 401查询失败即拒绝fail-closed查不到用户比如账户已被删除→ 该用户所有在途 Cookie 全部 401数据库抖动 → 返回 503 而不是放行。于是撤销所有会话从不可能变成了一次 1触发场景动作登出所有设备POST /auth/logout-alltoken_version 1本设备 Cookie 同时清掉修改密码SetUserPassword同一 SQL 语句内改密码 版本号 1邮件验证码重置密码ResetUserPassword改密码 标记邮箱已验证 版本号 1并删除全部 API Key改完密码或一键登出后攻击者手里哪怕还握着你三个月前的旧 Cookie下一次请求就会撞上版本号不匹配——旧令牌集体断粮。这正是无状态与可撤销兼得的关键设计。 相关实现middleware.go 中的resolveSession以及 auth.go 的LogoutAll集成测试 logout_all_integration_test.go 验证了一台设备登出全局另一台设备的令牌立即失效。三、账户征用Seizure抢注邮箱的人三条路全断这是 freehire 账号安全中最有特色的一条规则针对的是一个真实攻击场景攻击者抢先用自己账号的邮箱或随机挑一个真实存在的邮箱注册了一个账号从未验证邮箱。等真正的邮箱主人日后用 Google/GitHub 等 OAuth 登录时系统若简单地把身份合并到这个旧账号上等于把账户连同攻击者设置的密码一起拱手送人——这就是预劫持。freehire 的 OAuth 账号解析只认两条路且顺序固定身份优先先按(provider, provider_user_id)查外部身份已验证邮箱兜底身份没命中时才用邮箱匹配——但只接受提供商背书为已验证的邮箱未验证邮箱一律解析为无账户。当已验证身份 已验证邮箱落到了一个未验证、且有密码的旧账号头上时触发征用repository.go 调用 users.sql 中的SeizeUnverifiedAccount在同一个事务里同时发生三件事password_hash NULL密码直接销毁抢注者再也没法用密码登录token_version 1抢注者的所有在途会话全部作废DELETE FROM api_keys抢注者创建过的 API Key 全部删除这条最关键见下节。一句话总结你用一个没验证过的邮箱注册的账号一旦真主人带着已验证身份到来这个账号会被没收——密码毁掉、会话踢掉、密钥删光真主人平滑接管。四、API Key 的特例为什么撤销时要单独杀它freehire 允许用户创建 API Key 供程序调用。Key 落库时只存SHA-256 哈希 短前缀明文只在创建时展示一次认证时仅按token_hash expires_at匹配完全不查users表。这个设计对改密码/登出全局是合理的——Key 是长效程序凭据不该跟着人的会话一起死但它的副作用是token_version 1根本杀不死 API Key。所以 freehire 把两条账户易主的语句重置密码、账户征用都写成了带DELETE FROM api_keys的数据修改 CTE——删除和版本号自增被焊在同一条 SQL 里物理上无法只做一半。另外创建 Key 本身就要求邮箱已通过验证email_verified为真才允许插入堵住了抢注者趁未验证窗口偷偷铸造永不过期的 Key这条路。 约定文档明确警告不要顺手把tv查进 Key 认证里internal/identity/auth/AGENTS.md五、10 分钟最近认证证明敏感操作的二次门槛光有长期会话还不够如果你半小时前登录现在有人想解绑你的 Google 身份、改动安全设置仅凭一个还在有效期内的会话 Cookie 就放行是危险的。freehire 为此引入了一套独立的最近认证证明recentauth.go刚完成密码/OAuth 登录时签发一个10 分钟有效、一次性的hire_recent_authCookie证明被三重绑定用户 id 当前 token_version 当前这个具体会话的 SHA-256 指纹指纹要求令牌带jti老式无jti令牌会被拒绝敏感操作如解绑登录方式必须出示该证明并一次性消耗过期或已用过就返回428 recent_auth_required要求重新登录它从不接受 API Key 或 Bearer 令牌——机器凭据永远拿不到人是刚刚验证过的证明。这样即使攻击者偷到了一个长期有效的 Cookie想动解绑、改密这类高危操作还是得先骗到刚刚完成登录的那 10 分钟窗口。六、外围防线限流、验证码与恒定时间登录核心三条之外freehire 还在入口层堆了常规但扎实的防线速率限制登录 10 次/分钟、注册 5 次/分钟Redis 支持的 GCRA 限流器按 IP 计数⏱️验证码规则6 位邮件验证码15 分钟过期、错 5 次作废、60 秒重发冷却且按(user_id, purpose)分桶验证与重置互不覆盖⚖️恒定时间登录即使邮箱不存在也会跑一次针对 dummy 哈希的 bcrypt 校验让响应耗时不泄露该账号是否存在✅重置即验证收到重置验证码本身就证明邮箱控制权所以重置密码会同时把email_verified置为真——未验证账户从此不再是合并目标。 相关约定internal/identity/accounts/AGENTS.md、迁移文件 0041_account_security.sql七、源码速览关注点文件JWT 签发与校验sub/tv/jtiinternal/identity/auth/token.goCookie 读写HttpOnly; SameSiteLaxinternal/identity/auth/cookie.go认证中间件与版本比对internal/identity/auth/middleware.goOAuth 账号解析与征用触发internal/identity/accounts/repository.go重置密码 / 征用账户 SQLinternal/platform/db/queries/users.sql登出所有设备internal/api/handler/auth.go最近认证证明internal/identity/auth/recentauth/recentauth.go认证设计约定最佳阅读入口internal/identity/auth/AGENTS.md总结freehire 的账户接管防护可以浓缩成三层传输层——JWT 只走HttpOnlyCookieXSS 拿不到、CSRF 送不出去会话层——token_version让撤销一切会话退化成一次 1改密、登出全局、账户易主都会触发策略层——OAuth 只认已验证邮箱抢注未验证邮箱的账号会在真主人到来时被整户征用密码、会话、API Key 三条退路一次断干净高危操作再套一层 10 分钟一次性证明。对想自建登录体系的开发者来说这套无状态令牌 代际版本号 易主即全量销毁凭据的组合是一份很值得抄作业的参考答案。赞分享【免费下载链接】freehirefreehire — the open-source search engine for job seekers项目地址https://gitcode.com/GitHub_Trending/fr/freehire点击查看免费下载相关推荐如何轻松管理多用户认证Composio连接账户完整指南如何轻松管理多用户认证Composio连接账户完整指南 Composio 是一款强大的工具能够为智能代理提供精心设计的工具使其能够处理复杂任务。其中多用人工智能AI Agent工具调用mise bootstrap 账户管理用 [bootstrap.groups] 与 [bootstrap.users] 声明式管理 Linux 本地账户mise bootstrap 账户管理用 bootstrap.groups 与 bootstrap.users 声明式管理 Linux 本地账户 mise 的开发工具CLI多Agent账户管理如何用 standards-sdk 快速创建 HCS-15 Petal 账户一文搞定资金管理多Agent账户管理如何用 standards sdk 快速创建 HCS 15 Petal 账户一文搞定资金管理 本文介绍 standards sdk H上一篇全面认识MiniCPM-V-4.7-1B-OptiQ-4bitApple Silicon终极本地多模态视觉语言模型完全指南下一篇新秀earshot vs 老牌离线转写工具定位差在哪值不值得换看完这篇再决定创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。