如何在JWT中使用jti声明

时间:2015-03-06 21:18:24

标签: node.js rest express restful-authentication jwt

JWT规范提到了jti声称,据称可以用作防止重播攻击的随机数:

  

jti(JWT ID)声明为JWT提供唯一标识符。标识符值必须以确保将相同值偶然分配给不同数据对象的概率可忽略的方式分配;如果应用程序使用多个发行者,则必须在不同发行者生成的值之间防止冲突。 jti声明可用于防止重放JWT。 jti值是区分大小写的字符串。使用此声明是可选的。

我的问题是我将如何实现这一目标?我是否需要存储以前使用过的jtis并在每次请求时发出新的JWT?如果是这样,这不会破坏JWT的目的吗?为什么使用JWT而不是仅仅在数据库中存储随机生成的会话ID?

我的REST API有一个mongo数据库,我并不反对添加一个redis实例。是否有比JWT更好的身份验证选项?我主要只是不想在客户端上存储密码,这会消除HTTP身份验证作为选项,但是,随着我对这个JWT内容的深入了解,我开始感觉好像自定义令牌实现或不同标准可能更好适合我的需要。是否有基于令牌的身份验证的节点/快递包支持令牌撤销和旋转令牌?

非常感谢任何建议。

2 个答案:

答案 0 :(得分:9)

您可以使用express-jwt包

请参阅GitHubNPM上的express-jwt。

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);
  });

您还可以阅读第4部分。我们如何避免增加this oauth0 blog post的开销?

答案 1 :(得分:6)

这是一个古老的问题,但是我只是在做类似的事情。所以我将在这里分享我的想法。

首先,我同意在验证JWT令牌的同时进行数据库调用会破坏其无状态的主要优势。

以前的答案都没有提到刷新令牌,但是我相信它们在可伸缩性和安全性之间取得了很好的权衡。

简而言之,人们可以使用具有较短到期时间(例如15分钟)的常规身份验证令牌,并可以使用具有长期访问权限(例如2周)的刷新令牌。每当身份验证令牌过期时,刷新令牌(存储更安全)将用于生成新的身份验证令牌,而用户无需再次登录。

jti声明最适合刷新令牌。这样一来,您就可以在最小化数据库调用次数的情况下撤消访问。​​

假设平均用户会话为30分钟。如果您对常规身份验证令牌拥有jti声明,那么每个API调用都会至少进行一次额外的数据库调用,以检查该令牌是否未列入黑名单。但是,如果您仅对刷新令牌使用jti声明,则在30分钟的会话过程中,您将仅进行2个数据库调用以进行身份​​验证(假设每个auth令牌在15分钟后过期)。那是很大的区别。

关于实现,您可以使用随机生成的UID并将其用作表的主键。这样可以保证通话速度尽可能快。此外,您可以添加具有与expiration_time声明相同的值的exp列。这样,您可以轻松地(批量)删除所有过期的刷新令牌。

为什么使用JWT而不是仅将随机生成的会话ID存储在数据库中?

或者,如果我可以表述,“为什么要使用JWT刷新令牌而不是数据库中保存的随机字符串?”

我认为您可以做到,但是使用JWT令牌至少有两个优点:(1)如果令牌无效或已过期(在解码时),则根本不需要进行任何数据库调用。您只需返回带有错误状态代码的响应。 (2)如果您的系统很大,则可能会根据某些条件(例如,每个客户端应用程序[Web vs mobile])将“随机字符串”存储在不同的数据库表中。您如何知道要在其中查找随机字符串的表?使用JWT令牌,您只需添加一个client_id声明。因此,在令牌中包含信息的功能非常有用。