你的 JWT 方案安全吗?ASP.NET Core 刷新令牌机制详解

📅 发布时间:2026/7/16 12:47:54 👁️ 浏览次数:
你的 JWT 方案安全吗?ASP.NET Core 刷新令牌机制详解
在 ASP.NET Core 中做 API 认证时JWT 几乎是标配。它无状态、易扩展非常适合分布式系统。但很多项目在真正上线后才发现光有 Access Token 远远不够。如果访问令牌有效期太长一旦泄露风险极大如果太短又会频繁要求用户重新登录体验非常差。因此生产环境里通常会引入Refresh Token刷新令牌机制。它的作用很简单在不让用户重新登录的情况下安全地换取新的访问令牌①。这套机制的核心目标是在安全性与用户体验之间取得平衡。为什么需要刷新令牌访问令牌Access Token通常设置为 1530 分钟有效期。这样做的好处是一旦令牌被窃取攻击窗口会被大幅压缩。但问题也很明显如果用户正在操作系统15 分钟一到就被迫重新登录这在实际业务中是不可接受的。刷新令牌机制正是为了解决这个矛盾。第一客户端无需再次输入用户名和密码就可以通过刷新令牌换取新的访问令牌。 第二访问令牌保持短生命周期从源头降低泄露风险。 第三刷新令牌可以持久化并可控吊销实现精细化的会话管理②。两者职责非常清晰访问令牌负责“调用 API”刷新令牌负责“延续会话”。推荐的整体架构流程一个标准的 JWT Refresh Token 认证流程通常如下第一步用户提交用户名和密码登录。 第二步服务端验证成功后生成一个短期有效的 Access Token 和一个长期有效的 Refresh Token。 第三步将 Refresh Token 存入数据库Access Token 返回给客户端建议存于内存。 第四步当 Access Token 过期时客户端调用专门的/refresh接口用 Refresh Token 换取新的 Access Token。 第五步服务端验证 Refresh Token 的合法性若通过则返回新的令牌对并可选择执行“令牌轮换”Token Rotation③。这一整套流程是目前企业级 Web 应用的主流实践。实现步骤详解第一步定义刷新令牌模型刷新令牌必须持久化否则无法吊销。下面是一个典型的实体定义public class RefreshToken { public int Id { get; set; } public string Token { get; set; } // 唯一令牌值 public string UserId { get; set; } // 关联用户 public DateTime ExpiryDate { get; set; } // 过期时间 public bool IsRevoked { get; set; } // 是否已吊销 public DateTime CreatedAt { get; set; } // 创建时间 }实际生产环境中建议再增加ReplacedByToken、RevokedAt、CreatedByIp等字段方便审计和追踪。第二步生成安全令牌访问令牌通常使用 HMAC-SHA256 签名算法生成并设置 15 分钟有效期。刷新令牌则必须使用强随机数生成例如通过RandomNumberGenerator生成 64 字节随机数据再进行 Base64 编码。这样可以保证其不可预测性④。这里要强调一点刷新令牌不是 JWT它可以只是一个高强度随机字符串。第三步安全存储刷新令牌数据库中不要直接保存刷新令牌明文。最佳实践是对其进行哈希处理后再存储。即使数据库泄露攻击者也无法直接使用原始令牌。同时需要保存用户 ID 和过期时间便于后续校验与清理。第四步安全返回令牌给客户端响应中通常包含 Access Token 和 Refresh Token。Access Token 可以由前端保存在内存中。 Refresh Token 推荐存入HttpOnly Secure Cookie中这样浏览器 JavaScript 无法读取能有效防止 XSS 攻击窃取⑤。这是很多项目容易忽略却极其关键的一步。第五步实现刷新接口创建一个专用端点例如/refresh用于接收刷新令牌。服务端需要做以下校验刷新令牌是否存在。 是否未被吊销。 是否在有效期内。 所属用户是否仍然有效。校验通过后生成新的 Access Token 返回给客户端。第六步实施令牌轮换Token Rotation如果你只发一个长期有效的刷新令牌那它一旦泄露攻击者可以无限续期。因此推荐实施“令牌轮换”策略⑥每次使用刷新令牌成功后立即将旧令牌标记为IsRevoked true然后生成一个新的刷新令牌并持久化。这样即便旧令牌被截获也无法再次使用从根本上防止重放攻击。第七步登出时吊销令牌用户登出时应该主动将对应的刷新令牌标记为吊销状态。这样即使客户端仍保存令牌也无法再换取新的访问令牌。这一步是“彻底结束会话”的关键。安全最佳实践在真实生产环境中我通常建议遵循以下原则必须强制 HTTPS所有令牌传输都要加密。 刷新令牌必须存放在 HttpOnly Cookie 中。 数据库中只保存哈希后的刷新令牌。 访问令牌短期有效例如 15 分钟刷新令牌较长例如 7 天。 对/refresh接口增加限流防止暴力尝试⑦。 监控刷新令牌的异常使用行为例如同一个令牌被多次使用触发安全告警。这些措施组合在一起才能真正构建可靠的认证体系。常见错误与规避方式很多团队在实现时会踩一些典型坑。第一种错误是把访问令牌有效期设为几天甚至几个月。这等于放弃了 JWT 的安全优势。第二种错误是不把刷新令牌持久化。这样就无法实现吊销安全控制形同虚设。第三种错误是忽略令牌轮换。静态刷新令牌一旦泄露攻击者可以持续利用。第四种错误是把刷新令牌存进 LocalStorage。浏览器 XSS 一旦发生令牌就会被轻易窃取⑧。这些问题在代码层面看不明显但在安全层面是致命的。生产环境参考配置在云原生 SaaS 系统中比较常见的一套配置是访问令牌有效期15 分钟。 刷新令牌有效期7 天。 启用令牌轮换。 用户修改密码后自动吊销所有关联刷新令牌。 检测到刷新令牌重复使用时立即锁定账户并通知用户⑨。这种策略在安全性与用户体验之间达成了比较理想的平衡尤其适用于金融、电商、企业服务等对安全要求较高的系统。结语JWT 刷新令牌机制的核心思想是“职责分离”。短命的 Access Token 专注于 API 调用安全长命的 Refresh Token 专注于会话延续。通过数据库持久化、HttpOnly Cookie 存储、令牌轮换与吊销机制的组合你可以在 ASP.NET Core 中构建一套真正可用于生产环境的认证体系。这不仅是技术实现层面的设计更是现代 Web 安全架构的一种成熟实践⑩。参考资料① IETF.RFC 7519: JSON Web Token (JWT).https://datatracker.ietf.org/doc/html/rfc7519② OWASP.Session Management Cheat Sheet.https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html③ Microsoft.Authentication and authorization in ASP.NET Core.https://learn.microsoft.com/en-us/aspnet/core/security/authentication/④ NIST.Recommendation for Random Number Generation (SP 800-90A).⑤ PortSwigger.HttpOnly Cookies.https://portswigger.net/web-security/csrf/tokens#httponly-cookies⑥ Auth0.Token Rotation Best Practices.https://auth0.com/docs/secure/tokens/token-rotation⑦ Microsoft.Rate limiting middleware in ASP.NET Core.https://learn.microsoft.com/en-us/aspnet/core/performance/rate-limit⑧ Google.Web Security: Storing Tokens.https://web.dev/secure-token-storage/⑨ AWS.Best Practices for Managing JWTs.https://aws.amazon.com/blogs/security/best-practices-for-managing-jwts/⑩ IETF.RFC 6749: The OAuth 2.0 Authorization Framework.https://datatracker.ietf.org/doc/html/rfc6749