LOADING...
一种通过引入时间戳校验来解决JWT泄露后难以即时失效问题的技术方案。针对标准JWT无法手动禁用且可能存在多个有效凭证的缺陷,该方法在RTheme项目中利用lastUseAt字段,将登录时间戳同时存入数据库与Token荷载中。系统在验证时通过比对数据库记录与Token内的时间戳是否一致,确保只有最新的Token处于激活状态,从而实现一旦JWT泄露,用户只需重新登录即可立即使旧凭证失效的安全机制。
JWT很好用,在RTheme的使用场景中,登录操作可以由两种方式完成,分别是账号+密码或者使用JWT来更新登录信息,其中后者可用于实现“连续n小时未登录则退出登录状态”的效果。
但很遗憾,这就表明一旦你泄露了自己的JWT,丢失的JWT就可以被用于直接登录,直接更改账号密码也无济于事。
这主要是因为一个用户可以同时使用多个JWT导致的,而这很明显并不合理:
src/app/api/user/authorize/route.js:其中的关键位置是
这里我实际上在数据库中使用lastUset 存储了上次登录时的时间戳,此时间戳也会打包进JWT里面,在执行敏感操作时就可以这样核验此JWT是否为最新的JWT。因此就算JWT泄露,你通过重新使用密码登录的方式也可以让丢失的JWT无法用于继续登录。
这篇文章实际上是因为有个朋友正好问到相关的问题所以我稍微展开讲的,大家2025新年快乐。
// 登录模式分发
if (typeof infoJSON.token !== 'undefined') {
// JWT 刷新登录
// 检查传入的token
let tokenInfo;
try {
tokenInfo = token.verify(infoJSON.token);
} catch (err) {
if (err.name == 'TokenExpiredError') {
return Response.json(
{
message: 'TOKEN已过期,请重新登录',
},
{ status: 410 }
);
} else {
return Response.json(
{
message: 'TOKEN无效',
},
{ status: 400 }
);
}
}
// TOKEN有效,刷新TOKEN
if (tokenInfo) {
// 请求新信息
let result = await prisma.user.findUnique({ where: { uid: tokenInfo.uid } });
// 检查此Token是否为最新
if (result.lastUseAt == tokenInfo.lastUseAt + '') {
updateTime(result.uid, startTime);
return Response.json(
{
message: '登录成功',
info: pack(result, startTime),
token: token.sign(pack(result, startTime), infoJSON.expiredTime || '7d'),
},
{ status: 200 }
);
} else {
return Response.json(
{
message: 'TOKEN未处于激活状态',
},
{ status: 420 }
);
}
}
}if (result.lastUseAt == tokenInfo.lastUseAt + '') {
updateTime(result.uid, startTime);
// ...
}
评论