浏览器免重登:HttpOnly cookie + 服务端 session 表 + 设备名持久化
- 新增 web_sessions 表(sqlc):refresh_token 以 AES-256-GCM 落盘,密钥取自 CDROP_SESSION_SECRET(env、不在库内);cookie 仅存不透明随机串,表 id 存其 SHA-256,故 DB 单独泄露既换不出可用 cookie、也解不出 token - /auth/exchange 建 session 并下发 HttpOnly; Secure; SameSite=Lax; Path=/api/auth cookie,响应体不再回传 refresh_token - /auth/refresh 改为 cookie 驱动(7 天滑动失活),同时即开机静默免重登; 新增 /auth/logout(删 session + 清 cookie)、/auth/device(写设备名入 session) - device_name 随 session 存,开机 refresh 带回前端,抗 iOS PWA 存储清除; setup / 改名时 syncWebDeviceName 推送服务端 - striped per-session 锁串行化同会话并发 refresh,防一次性 refresh_token 被 花两次而把用户从所有 tab 登出 - 前端 store 移除 refreshToken 字段(长寿命凭据彻底不进 JS);main.tsx 首屏前 bootstrapAuth 用 cookie 静默续期,命中直接进已登录态、避免登录页闪现 - config:prod 强制 CDROP_SESSION_SECRET,缺失拒启动 - 桌面端不受影响(自有 loopback flow + Go keyring,不碰这两个端点)
This commit is contained in:
@@ -43,6 +43,13 @@ type Config struct {
|
||||
|
||||
HS256Secret string `koanf:"hs256_secret"`
|
||||
|
||||
// SessionSecret keys the AES-256-GCM encryption of browser refresh_tokens at
|
||||
// rest in web_sessions (the "passwordless re-login" feature). Any-length
|
||||
// high-entropy string; it's SHA-256'd into a 32-byte key. The key lives only
|
||||
// here (container env), never in the DB file, so an exfiltrated SQLite file
|
||||
// can't be decrypted. Required in prod — refuse to boot without it.
|
||||
SessionSecret string `koanf:"session_secret"`
|
||||
|
||||
// Shortcut tokens:iOS 快捷指令用的长效 HS256 token。TTLDays 是签发有效期
|
||||
// (默认 365 天),MaxPerUser 是每用户未吊销且未过期的 token 上限(默认 10)。
|
||||
// 需配 HS256Secret 才启用,否则签发端点返回 503。
|
||||
@@ -127,6 +134,14 @@ func (c *Config) validate() error {
|
||||
"CDROP_AUTH_MODE=prod requires CDROP_OIDC_AUDIENCE " +
|
||||
"(comma-separated OAuth client_ids); refusing to start")
|
||||
}
|
||||
// SessionSecret keys at-rest encryption of browser refresh_tokens. Empty
|
||||
// would either disable passwordless re-login or, worse, tempt a plaintext
|
||||
// fallback; require it so the encryption path is always live in prod.
|
||||
if c.SessionSecret == "" {
|
||||
return errors.New(
|
||||
"CDROP_AUTH_MODE=prod requires CDROP_SESSION_SECRET " +
|
||||
"(keys web-session refresh_token encryption); refusing to start")
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("CDROP_AUTH_MODE must be \"dev\" or \"prod\", got %q", c.AuthMode)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user