Skip to content

Security Model

何家欢 edited this page Jun 17, 2026 · 3 revisions

Security Model

本页解释 Passkey-Auth 的安全模型、已做保护和仍需注意的边界。

信任边界

可信后端:

  • Passkey-Auth Flask 服务
  • 业务系统后端
  • 数据库

不可信输入:

  • 浏览器 URL 参数
  • 前端 JavaScript 传来的 credential JSON
  • callback 参数中的 status=success
  • 用户输入的 username

核心原则:

  • 浏览器负责完成 WebAuthn ceremony,但最终身份必须由后端判断。
  • URL 里的成功状态不能直接登录。
  • code 和 challenge 必须一次性消费。
  • client secret 和 server token 永远只在后端。

WebAuthn 保护

注册:

  • 使用 generate_registration_options
  • resident key required
  • user verification preferred
  • attestation none,减少隐私暴露
  • exclude existing credentials,避免重复注册

登录:

  • 使用 generate_authentication_options
  • 验证 challenge、RP ID、origin、public key、sign count
  • 用户名登录时限制 allowCredentials
  • 无用户名登录时通过 user handle 反查用户

相关代码:

passkey_demo/webauthn_service.py

OAuth Code 保护

authorization code:

  • 随机生成
  • 数据库存 hash
  • 绑定 client_id
  • 绑定 redirect_uri
  • 有 TTL
  • 只能消费一次

换 token 时会校验:

  • client 是否存在
  • client secret 是否匹配
  • redirect_uri 是否匹配
  • code 是否未过期、未消费

Link Challenge 保护

challenge request:

  • 随机 challenge id
  • 保存 username、state、return_uri、client_id
  • 有 TTL
  • completed 和 consumed 分离
  • callback 校验后才 consumed

challenge result:

  • 使用 Flask SECRET_KEY 通过 itsdangerous.URLSafeTimedSerializer 签名
  • 绑定 challenge_id
  • 绑定 client_id
  • 绑定 state
  • 绑定用户 idsub

callback 必须校验签名和数据库状态,不要信任 status=success

CSRF 防护

OAuth 和 link challenge 都使用 state

  • 业务站点生成随机 state
  • 保存到业务 session
  • callback 先校验 state
  • state 失败直接拒绝

不要复用 state,不要把 state 固定写死。

注册保护

注册默认关闭:

PASSKEY_REGISTRATION_ENABLED=false

UI 层还有隐藏入口和短期解锁:

  • POST /api/ui/intent
  • GET /api/ui/register-client.js
  • REGISTER_UNLOCK_TTL_SECONDS

这不是强安全认证,只是降低公开页面被随意注册的概率。真正生产系统应增加管理员审批、邀请码或后台用户管理。

Token 和密钥

FLASK_SECRET_KEY 影响:

  • Flask session
  • OAuth access token
  • challenge result token

生产要求:

  • 固定配置
  • 强随机
  • 不提交到 git
  • 不随意更换

更换后影响:

  • 旧 session 失效
  • 旧 access token 失效
  • 未完成的 challenge result 失效

已知边界

当前项目是轻量认证服务,不是完整 IdP 产品。生产扩展建议:

  • 多 client 管理
  • client secret hash 存储
  • refresh token
  • token revocation
  • audit log
  • rate limiting
  • admin console
  • 数据库迁移工具
  • 更严格的 CSP、安全 header
  • 反向代理 HTTPS 强制跳转

安全检查清单

  • 业务 callback 已校验 state
  • token 只在后端换取
  • client_secret 不出现在浏览器
  • PASSKEY_SERVER_API_TOKEN 不出现在浏览器
  • callback URL 精确白名单
  • code/challenge TTL 足够短
  • 数据库不会被公开下载
  • .env、SQLite、.venv 不提交
  • 注册默认关闭
  • HTTPS 正常

Clone this wiki locally