nw.*_*nw. 53 rest restful-authentication node.js express jwt
JWT规范提到了jti声称,据称可以用作防止重放攻击的随机数:
jti(JWT ID)声明为JWT提供唯一标识符.标识符值必须以确保将相同值偶然分配给不同数据对象的概率可忽略的方式分配; 如果应用程序使用多个发行者,则必须在不同发行者生成的值之间防止冲突.jti声明可用于防止重放JWT.jti值是区分大小写的字符串.使用此声明是可选的.
我的问题是如何实现这一目标?我是否需要存储以前使用过的jtis并在每次请求时发出新的JWT?如果是这样,这不会破坏JWT的目的吗?为什么使用JWT而不是仅仅在数据库中存储随机生成的会话ID?
我的REST API有一个mongo数据库,我并不反对添加一个redis实例.是否有比JWT更好的身份验证选项?我主要只是不想在客户端上存储密码,这会消除HTTP身份验证作为选项,但是,随着我对这个JWT内容的深入了解,我开始感觉好像自定义令牌实现或不同标准可能更好适合我的需要.是否存在基于令牌的身份验证的任何节点/快速包,它们支持令牌撤销和旋转令牌?
非常感谢任何建议.
小智 45
实际上,存储所有已发布的JWT ID会破坏使用JWT的无状态特性.但是,JWT ID的目的是能够撤销先前发布的JWT.这可以通过黑名单而不是白名单来实现.如果您已经包含了"exp"声明(您应该),那么您最终可以清理列入黑名单的JWT,因为它们会自然过期.当然,您可以同时实施其他撤销选项(例如,基于"iat"和"aud"的组合撤销一个客户端的所有令牌).
amu*_*uzi 13
这是一个老问题,但我只是在做类似的事情。所以我会在这里分享我的想法。
首先,我同意在验证 JWT 令牌的同时进行数据库调用会破坏其无状态的主要优势。
之前的答案都没有提到刷新令牌,但我相信它们在可扩展性和安全性之间提供了很好的权衡。
简而言之,可以使用具有较短到期时间(例如 15 分钟)的常规身份验证令牌,并使用长期访问(例如 2 周)刷新令牌。每当身份验证令牌过期时,刷新令牌(更安全地存储)用于生成新的身份验证令牌,而无需用户再次登录。
该jti声明最适合刷新令牌。这使您能够撤销访问权,同时最大限度地减少进行的数据库调用次数。
假设平均用户会话是 30 分钟。如果您jti声明了常规身份验证令牌,那么每个 API 调用都会执行至少一次额外的数据库调用,以检查令牌是否未列入黑名单。但是,如果您只jti对刷新令牌使用声明,则在 30 分钟的会话过程中(假设每个身份验证令牌在 15 分钟后过期),您将只进行 2 次数据库调用以进行身份验证。这是一个很大的不同。
关于实现,您可以使用随机生成的 UID 并将其用作表的主键。这保证了调用尽可能快。此外,您可以添加expiration_time与声明具有相同值的列exp。这样您就可以轻松(批量)删除所有过期的刷新令牌。
为什么要使用 JWT 而不是将随机生成的会话 ID 存储在数据库中?
或者,如果我可以解释一下,“为什么要使用 JWT 刷新令牌而不是保存在数据库中的随机字符串?”
我认为您可以做到这一点,但使用 JWT 令牌至少有两个优点:(1) 如果令牌无效或过期(当您对其进行解码时),您根本不必进行任何数据库调用。您只需返回带有错误状态代码的响应。(2) 如果您有一个大型系统,您可能会根据某些标准将“随机字符串”存储在不同的数据库表中(例如,每个客户端应用程序 [web vs mobile])。你怎么知道在哪个表中查找随机字符串?使用 JWT 令牌,您可以简单地添加client_id声明。因此,在令牌中包含信息的能力是有用的。
Yve*_* M. 11
Express-jwt处理撤销的令牌,如下所述:https://github.com/auth0/express-jwt#revoked-tokens
var jwt = require('express-jwt');
var data = require('./data');
var utilities = require('./utilities');
var isRevokedCallback = function(req, payload, done){
var issuer = payload.iss;
var tokenId = payload.jti;
data.getRevokedToken(issuer, tokenId, function(err, token){
if (err) { return done(err); }
return done(null, !!token);
});
};
app.get('/protected',
jwt({secret: shhhhhhared-secret,
isRevoked: isRevokedCallback}),
function(req, res) {
if (!req.user.admin) return res.send(401);
res.send(200);
});
Run Code Online (Sandbox Code Playgroud)
您还可以阅读第4部分.我们如何避免增加开销?来自这篇oauth0博文.