为什么 openGym 放弃密码WebAuthn Passkey 登录原理与安全设计解析【免费下载链接】openGymhttps://github.com/DuarteSantos8/openGym项目地址: https://gitcode.com/gh_mirrors/ope/openGymopenGym 是一个自托管的健身房与体重追踪工具它彻底放弃了传统密码改用 WebAuthn Passkey生物识别密钥登录你用 Face ID 或指纹就能解锁自己的训练数据服务器上不存任何密码。本文面向新手用大白话讲清这套 Passkey 登录的工作原理以及它背后的 6 个关键安全设计帮你理解免密登录为什么反而更稳。1. 为什么一个自托管健身应用不适合用密码大部分健身 App 会把账号密码存在别人的服务器上数据也跟着一起被绑架。而 openGym 的设计哲学是数据放在你自己的机器上登录方式不能成为短板。密码方案对自托管场景尤其不友好密码会被复用——你不太可能为家里这台健身 App 专门想一个新密码大概率复用别站的弱密码泄露面大——一旦./data目录里的密码哈希被拖库用户还得改密码、收验证邮件体验差——手机上每次登录都要敲键盘和举起手机刷个脸就进的直觉相去甚远。openGym 的登录页只留下两个按钮「用 Passkey 登录」和「创建新档案」见 Login.jsx甚至给不支持 Passkey 的浏览器也留了「免账号继续」的本地模式兜底。2. 什么是 Passkey一句话版原理Passkey 基于WebAuthn标准核心是一条公钥-私钥配对角色存在哪作用私钥你的手机安全芯片 / 密码管理器iCloud 钥匙串、Google 密码管理器等对每次登录挑战做签名永远不离开设备公钥服务器db.json里的creds列表用来验证签名是否有效登录时服务器发来一段一次性的考题challenge你的设备用私钥作答签名服务器拿公钥验答案。因为私钥从不上网所以没有可被窃听、可被拖库的东西——这也是 openGym 在 README 里强调的Passkey 私钥永远不碰服务器。 顺带一提openGym 的独立 Android 应用无服务器版连登录这一步都没有数据直接存在手机里见 docs/MOBILE.md。3. 一次 Passkey 登录的完整流程前端逻辑集中在 api.js整个握手只有 4 步请求登录选项浏览器调用POST /api/login/options服务器生成一次性 challenge 并返回设备签名浏览器弹出系统级认证框Face ID / 指纹安全硬件用私钥对 challenge 签名提交凭证前端把签名结果clientDataJSONsignature等发回POST /api/login/verify验证发 Cookie服务器验签通过更新签名计数器下发一个签过名的会话 Cookie登录完成。服务端对应的注册 / 登录路由在 server.js实现只依赖一个库simplewebauthn/server没有引入任何框架。4. 安全设计逐条拆解4.1 服务器只存公钥密码零存储注册成功后服务器落盘的只是公钥、签名计数器和传输方式见 server.js。数据文件 db.json 里翻遍也找不到任何秘密——这就是放弃密码敢说的底气。4.2 Challenge 一次性且限时防重放攻击每个 challenge 存内存 Map 中5 分钟过期且takeChallenge取出即删除server.js。有人截获你某次登录的签名报文再重发对不起考题已被用过并销毁验证直接失败。4.3 签名 Cookie 版本号支持全设备登出登录后服务器下发的不是随机 token而是用 HMAC-SHA256 签名的 Cookieserver.js载荷格式是用户ID:过期时间:版本号服务端用timingSafeEqual做恒定时间比对杜绝时序侧信道点一次「在所有设备登出」POST /api/logout/all该用户的版本号sv加 1server.js之前签发过的所有 Cookie 瞬间全部失效——手机丢了也不怕用 Passkey 刷脸即可立即重新登录无需改任何密码。4.4 会话有效期取 90 天便利与风控的平衡默认SESSION_DAYS90server.js每周练几次的人可以一次登录永久有效但就算 Cookie 被盗攻击窗口也被压在 90 天内。Cookie 同时带HttpOnly、SameSiteLaxHTTPS 下再加Secure基本封死了 XSS 偷 Cookie 和跨站提交的常见路子。4.5 计数器防凭证克隆每次登录验证后服务器会把该凭证的签名计数器更新为最新值server.js。如果攻击者偷偷复制了你的凭证cloning两边的计数器会打架验证时即可发现异常。4.6 邀请码把注册入口也设计成安全件自托管实例可开启INVITE_ONLY模式SELF_HOSTING.md。注意邀请码的生成方式16 位十六进制64 位随机数而且在发选项和验证成功两个时点各校验一次再核销server.js——因为应用本身不做限流所以代码本身必须不值得被猜这是很典型的小团队安全思维。5. 两个新手最容易踩的坑现象原因与解法手机上死活弹不出 Passkey 框Passkey 要求HTTPS仅http://localhost例外局域网 IP HTTP 不行。给自己的实例配一个 HTTPS 域名即可详见 docs/SELF_HOSTING.md 第 3 节登录提示 verification failed.env里的RP_ID/ORIGIN和浏览器地址栏对不上。Passkey 绑定的是精确主机名改域名后旧 Passkey 也会作废选域名请在用户注册之前想清楚一句话记忆Passkey 认域名、认 HTTPS不认 IP。6. 写在最后openGym 的登录方案可以浓缩成三句话 私钥永远在设备里服务器只有公钥密码泄露无从谈起️ 一次性 challenge 签名 Cookie 版本号 计数器重放、盗 Cookie、凭证克隆三条攻击线全部设防⚡ 对用户的代价只是一次刷脸换来的是 90 天免登录和一键全设备登出。这套实现总共只有一个后端依赖、约 550 行无框架 Node 代码api/server.js如果你想给自己的自托管项目加免密登录它是一份非常值得参考的轻量范本。部署配置入口是 docker-compose.yml完整配置项见 SELF_HOSTING.md。【免费下载链接】openGymhttps://github.com/DuarteSantos8/openGym项目地址: https://gitcode.com/gh_mirrors/ope/openGym创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考