控制台会话
- 会话保存在数据库(Spring Session JDBC),浏览器只持有
GRANTFORGE_SESSIONCookie:HttpOnly、SameSite=Lax,HTTPS 下带 Secure(或用grantforge.security.cookie-secure强制)。 - 登录、完成两步验证、完成联合登录时都会更换会话 ID 与 CSRF 令牌,防止会话固定。
- 状态修改请求必须带
X-XSRF-TOKEN头,值来自XSRF-TOKENCookie。 - 管理员可以列出并结束任何会话;禁用、锁定、重置密码会立即结束该账号的全部会话;修改密码会结束其他设备上的会话。
密码
- 新密码用 Argon2id 哈希;仍能校验 BCrypt 与 1.x 导入的哈希,并在下次登录时升级为当前算法。
- 策略:长度、字符类别、历史记录、有效期均可配置,密码不能包含用户名。
- 连续失败达到次数后锁定账号;未知用户名也执行一次哈希比较,响应时间不暴露哪些用户名存在;停用账号与停用租户只有在密码正确后才会提示。
两步验证与再次验证
- TOTP(RFC 6238,SHA-1、6 位、30 秒,前后各容忍一个时间步),同一个时间步的验证码只能用一次;10 个一次性恢复码以 SHA-256 保存。
- 开启两步验证的账号,密码正确后会话处于“待完成”状态 5 分钟,完成第二步之前不是登录状态。
- 敏感接口用
@RequireStepUp标注:开启两步验证的账号需要在可配置的时间窗内验证过,否则返回GF-SECURITY-006,控制台弹窗确认后重试。
加密存储
身份源的绑定密码与客户端密钥、验证器密钥、数据服务的敏感配置、授权服务器的签名私钥都用 AES-GCM 加密后保存。密钥来自 grantforge.security.encryption-key;未配置时自动生成并保存在数据库中(仅适合试用)。代理令牌与 OAuth 客户端密钥只保存哈希。
令牌
- 授权服务器保存令牌的哈希,而不是令牌本身。
- 刷新令牌一次一换,旧令牌被重放时吊销整个授权。
- 账号停用、锁定、需要改密,客户端停用,租户停用,都会阻止令牌续期;开放 API 每次调用都会确认令牌仍然有效。
- 策略快照用 Ed25519 签名,代理验证签名后才使用。
接口防护
- 每个接口必须声明访问方式,没有声明的接口无法启动;需要权限的接口在每次调用时按最新快照检查。
- 被拒绝的调用写入审计(不阻塞请求)。
- 外部身份源的同名本地账号不会被自动关联,防止账号接管。
- 导出 CSV 时以
=、+、-、@开头的单元格加前缀,防止公式注入。
审计
所有管理操作、授权变更、登录事件与被拒绝的调用都记录在审计日志中;权限相关的变更与它的审计在同一个事务内提交,变更回滚则审计也不会留下。
