认证、Session 与 JWT:身份状态怎样建立、验证、撤销和升级
贯通密码验证、MFA、Session 固定防护、JWT 验证、撤销、轮换与认证强度升级。
NIST SP 800-63B-4 区分认证因子、重放与抗钓鱼能力;RFC 8725 要求 JWT 固定算法、校验 issuer 与 audience,并为不同用途建立互斥验证规则。
凭证验证不是字符串比较
密码验证器保存带盐的抗离线破解派生值,限制尝试速率并拒绝常见泄露值;强制大小写符号组合与周期轮换不能替代长度、泄露检测和多因素认证。恢复流程与客服改密拥有同等账户接管能力,必须采用更强证据、冷却期和告警。
MFA 要区分“两个输入”和“两个独立因子”。密码加 PIN 仍是同类知识因子;手工输入 OTP 可抗简单重放,却不天然抗钓鱼中继。高风险管理、支付和秘密读取应采用与验证方绑定的抗钓鱼认证,并在风险变化时 step-up。
Session 是服务端可撤销状态
登录成功后应轮换 session id,防止攻击者预置标识;Cookie 使用 Secure、HttpOnly 和合适的 SameSite,并限制 Domain/Path。会话同时受空闲时限、绝对时限、设备并发、密码变更与账户冻结影响。退出不是删除浏览器 Cookie 就结束,服务端状态必须失效。
分布式 Session 需要版本与权威撤销。缓存不可用时,高风险请求默认拒绝,不能把“查不到会话”降级为匿名可写。会话 id、刷新令牌和认证器输出不得进入普通日志。
JWT 验证是一组互锁约束
资源服务先固定允许算法和密钥来源,再验证签名、issuer、audience、用途、时间窗口和必要声明。不能接受 token 自报算法,不能让 ID Token 当 Access Token,也不能只 decode payload。kid 只用于受控密钥集合查找,不能成为文件名、URL 或数据库表达式。
自包含令牌仍需撤销模型:短 access token 配合可轮换 refresh token;用户保存 securityVersion;高风险操作查询权威状态;密钥轮换保留有界双钥窗口。签名有效但 securityVersion 已落后时,身份状态已经失效。
认证生命周期从注册延伸到恢复和注销
注册要验证标识归属并防批量占用;认证器绑定记录时间、设备、强度和恢复方法;新增认证器通常要求现有强认证或带冷却的人工流程。删除最后一个强认证器、修改恢复邮箱和导出恢复码都是高风险动作,不能只凭当前弱会话完成。
密码派生参数随硬件提升而升级。登录成功时若发现旧参数,在同一次已验证流程中重算;验证失败不泄露账号是否存在。速率限制按账号、来源和设备分层,避免攻击者用大量账号绕过单账号阈值,也避免只按共享出口 IP 锁死合法组织。
会话与令牌迁移需要兼容窗口
Session Schema 增加 securityVersion 或认证强度时,先让读取端理解新旧记录,再切换写入;JWT 新增 audience、typ 或 key 时,资源服务先部署严格但兼容的双验证器,观察旧 token 归零后移除旧规则。双验期间规则必须按用途分开,不能写成“新失败就用宽松旧逻辑”。
密钥泄露处置按 kid 定位签发窗口,停止签发、缩短缓存、撤销刷新链并决定是否提升全体 securityVersion。审计要回答哪些主体、受众和资源接受过该 key,而不是只知道密钥已经轮换。
账户枚举与自动化攻击从响应差异进入
登录、注册、找回和 MFA 校验要统一对外语义与近似时延,内部仍记录账号不存在、密码错误、锁定或风险拒绝。完全相同时延并不现实,但不能让数据库快速 miss 与昂贵密码派生形成稳定可测差异;可对不存在账号执行固定的伪派生,并对所有路径应用相同速率预算。
锁定策略需要防攻击者恶意锁死他人。短期退避、分层限速、风险挑战和告警通常比永久锁定安全;管理员解锁也必须验证操作者与原因。认证成功后重置哪些计数、跨区域计数如何收敛、限流存储故障时是拒绝还是降级,都要进入状态机。
JWT 的时间和密钥缓存会制造隐蔽窗口
exp、nbf 与 iat 依赖资源服务器时钟,允许的 clock skew 应有界并监控;不能为了处理时钟故障把容差扩大到数小时。JWKS 缓存既要避免每次请求远程获取,又要在新 kid 出现时受控刷新。未知 kid 攻击可能放大到上游,刷新使用单航班、速率限制与最后已知好集合。
不同发行者即使使用相同算法也不能共享一套宽松验证器。每个 issuer 固定 discovery/JWKS 来源、audience、token type、必要 claim 与权限映射;角色或 scope 映射失败默认无权限。灰度迁移先部署能识别新 issuer/key 的读取端,再切签发,旧 key 的接受窗口由最长 token 生命周期和撤销计划共同决定。
认证事故必须能按状态分层止血
凭证填充激增时先限制登录与找回,保护密码派生线程池和通知通道;疑似单用户接管时提升该用户 securityVersion、撤销 refresh family、冻结敏感操作并保存审计;签名 key 泄露时停止签发、撤销 key、评估最长 token 窗口并决定全局重新认证。三种事故的爆炸半径不同,不能都靠“重启服务”。
会话看板至少拆登录成功/失败原因、MFA challenge、恢复、Session 创建/轮换/撤销、JWT issuer/audience/algorithm/kid 拒绝、securityVersion 拒绝和 refresh replay。指标标签不放用户名、token 或 session id;个体调查通过受控审计关联。告警同时观察绝对量和每主体/来源速率,避免大客户正常登录被误判。
容量压测包含正确密码与错误密码混合、JWKS 冷缓存、集中 Session 延迟和大规模撤销。认证依赖失效时预先定义哪些只读会话可短时继续、哪些管理操作必须拒绝,以及恢复后如何清理本地缓存。
安全状态机必须让失败停在安全位置
一次安全决策沿“解析—认证—授权—执行—审计”推进。任何阶段超时或证据不足都不能伪装成允许;同时要区分未认证、无权限、输入拒绝、依赖不可用和结果未知,避免客户端盲目重试。
反向验证要证明旁路也被关闭
测试不止提交非法字符串,还要更换租户、对象、HTTP 方法、内容类型、转发头、异步线程、重定向目标和旧版本凭证;在认证服务、审计存储、DNS、密钥源和策略缓存超时时观察默认行为。拒绝必须无业务副作用,错误响应不泄露资源存在性或内部实现。
容量同样属于安全边界。密码派生、签名验证、文件扫描、令牌内省和审计写入都可能被放大;为主体、租户、IP、操作和下游分别设置预算,并记录拒绝原因。限流不能只按可伪造 Header,也不能让攻击流量占满合法用户恢复通道。
生产证据与治理
上线门禁要求:威胁场景有 owner;允许和拒绝路径都有测试;默认拒绝与应急旁路已演练;秘密可轮换;审计可查询且防越权;依赖与构件来源可证明;旧版本兼容窗口和撤销路径明确。安全控制只有在故障、升级和应急状态仍成立时才算完成。
用两个 Java 17 模型固定安全不变量
模型不尝试实现密码算法或攻击载荷,只把控制输入、判定顺序和确定输出固化,真实系统再替换为框架、密钥服务与持久化策略。
javac --release 17 -Xlint:all -Werror examples/backend-development/security/auth-session-jwt/PasswordVerifierDemo.java examples/backend-development/security/auth-session-jwt/TokenRevocationDemo.java
java -cp examples/backend-development/security/auth-session-jwt PasswordVerifierDemo
java -cp examples/backend-development/security/auth-session-jwt TokenRevocationDemopasswordLength=16 blocklisted=false saltedHash=true rateLimited=true authenticated=true
tokenVersion=7 currentVersion=8 signatureValid=true active=false reason=SECURITY_VERSION_REVOKED输出变化必须对应一条明确策略或迁移决定;禁止为了让测试通过而放宽 issuer、audience、tenant、路径、算法或来源校验。
把控制成本写进容量与事故恢复
“身份可信度来自完整验证链,令牌可读或签名正确都不足以证明当前仍有权限”不是免费承诺。认证与密码派生消耗 CPU,远程策略和 Session 占用连接,签名与哈希增加计算,扫描和隔离消耗磁盘与队列,审计增加写放大。容量模型按峰值合法流量叠加恶意放大:每请求验证次数、下游往返、最大输入、并发隔离任务、失败重试、日志体积和安全状态保留期。平均延迟正常而拒绝队列持续增长,仍然意味着控制即将失效。
安全依赖使用独立舱壁与 deadline,不能与普通业务共用无界线程池。缓存只能保存带版本且可撤销的结论;认证、授权或密钥源不可达时,根据资产等级预先定义拒绝、只读、使用最后已知好策略或进入人工审批,禁止在事故中临时改成全放行。应急旁路必须强认证、最小范围、自动过期并产生高优先级审计。
事故恢复按“阻止继续扩大—保存证据—撤销资格—修复权威状态—重建派生状态—验证不变量”推进。只修代码却不撤销 token、secret 或错误策略缓存,攻击窗口仍然存在;只轮换凭证却不检查已发生业务写,也无法证明资产恢复。对 PasswordVerifierDemo 与 TokenRevocationDemo 对应的决策输出建立线上指标或审计查询,才能把模型与生产证据连接起来。
升级时先部署严格兼容的读取端,再切换签发者或写入端,观察旧版本使用归零后删除兼容分支。任何临时兼容都记录 owner、截止、拒绝指标和回滚条件;为了兼容而跳过验证不属于迁移策略,而是新增旁路。
