如何在某人更改密码后使用户的 JWT 令牌无效
Posted
技术标签:
【中文标题】如何在某人更改密码后使用户的 JWT 令牌无效【英文标题】:How to invalidate a JWT token of a user after password is changed by someone 【发布时间】:2020-03-27 21:57:43 【问题描述】:我创建了一个使用 JWT 身份验证的 MVC 页面。用户成功登录后,应用程序会向用户返回存储在请求标头中的 JWT 令牌。但随后出现了问题。另一个人也使用相同的用户帐户登录并更改密码。因此,由于安全问题,应终止第一个登录会话。我认为的解决方案是使该用户的 JWT 令牌无效。但我必须定义用户密码何时更改。 JWT 令牌不包含密码信息,因此我无法请求后端服务器确定每次用户(使用旧密码)向服务器请求时更改密码。我需要一些想法和建议。
【问题讨论】:
一种方法是将密码哈希(应该加密)存储在 JWT 中,并在每次请求时将其与数据库中的哈希值进行比较。您可以将有效负载添加到 JWT Waaaaait 等一下...多个人以同一用户身份登录?这听起来完全,首先对我来说完全错误。这听起来像是XY problems 的母亲。人们应该将用户及其身份验证与授权分离是有原因的。但是,作为要点:在服务器端存储会话信息并保留与其关联的有效 JWT 列表。 @MarkusWMahlberg 使用多个设备登录并使用其中一个设备与没有“气味”的情况基本相同。如果您丢失了其中一台设备,您可能需要更改密码以使其他所有令牌失效。 @Jesper 真的。感谢您的澄清。然而,同样的原则也适用。引用令牌,使引用无效,问题已解决。 【参考方案1】:在 jwt 中使用密码作为声明? 每次请求都会检查,所以修改密码后会返回401
【讨论】:
【参考方案2】:对于此功能,您应该在用户表上添加新属性,如 SerialNumber 作为字符串
public class User public string SerialNumber get; set;
当您想为用户创建新令牌时,将用户序列号添加到这样的声明中
new Claim(ClaimTypes.SerialNumber, user.SerialNumber, ClaimValueTypes.String, issuer),
当更改用户密码或用户名或状态或每个重要属性时,您应该更新序列号。在第一次 http 请求后对令牌验证器方法进行串行更改时,将引发错误代码 401(表示未经授权)
public async Task ValidateAsync(TokenValidatedContext context)
var claimsIdentity = context.Principal.Identity as ClaimsIdentity;
if (claimsIdentity?.Claims == null || !claimsIdentity.Claims.Any())
context.Fail("This is not our issued token. It has no claims.");
return;
var serialNumberClaim = claimsIdentity.FindFirst(ClaimTypes.SerialNumber);
if (serialNumberClaim == null)
context.Fail("This is not our issued token. It has no serial.");
return;
var userIdString = claimsIdentity.FindFirst(ClaimTypes.UserData).Value;
if (!int.TryParse(userIdString, out int userId))
context.Fail("This is not our issued token. It has no user-id.");
return;
var user = await _signInService.GetUserAsync(userId);
if (user == null)
context.Fail("User deleted!");
return;
if (user.SerialNumber != serialNumberClaim.Value || !user.Status)
context.Fail("This token is expired. Please login again.");
return;
关于 JWT Token 配置
OnTokenValidated = context =>
var tokenValidatorService = context.HttpContext.RequestServices.GetRequiredService<ITokenFactoryService>();
return tokenValidatorService.ValidateAsync(context);
,
【讨论】:
【参考方案3】:直接在令牌中使用密码存在安全风险,因为攻击者可以从用户的计算机中检索它。最好:
在令牌中包含一个唯一的令牌 ID,并维护一个已撤销令牌(或允许的令牌;以更合适者为准)的列表。 或 在用户列表中包含“版本号”,在更改密码时更改它,并在颁发令牌时包含版本号。这样,所有旧令牌都可以被拒绝。 @Mohammad 的回答有一个类似的例子。这些信息本身没有任何意义。
【讨论】:
以上是关于如何在某人更改密码后使用户的 JWT 令牌无效的主要内容,如果未能解决你的问题,请参考以下文章