我有一个带有Angular 前端的nodejs api.API成功地使用JWT和passport来保护其端点.

我现在意识到,在令牌过期后,我的前端仍将允许用户请求我的api端点,而无需提示他们重新输入登录详细信息以获取新令牌.

以下是我的后端如何生成令牌:

function generateToken(user) {
  return jwt.sign(user, secret, {
    expiresIn: 10080 // in seconds
  });
}

所以为了实现这个逻辑,我想我需要在客户端验证JWT令牌.问题1:这是一种明智的做法吗.

问题2:我正在使用的JWT库似乎需要公钥才能使用它的verify()函数.我似乎没有公钥,只有一个秘密,这是我编造的,所以它不是用一对密钥生成的.我的公钥来自哪里,或者有没有其他方法可以在没有公钥的情况下验证我的令牌?

这一切似乎都应该是显而易见的,我错过了一些东西,所以如果这是一个愚蠢的问题,我道歉,但我似乎找不到答案?

推荐答案

TL;DR

  1. 您必须在server always中填写JWS的签名.
  2. Client-side signature verification不会给你带来太多,除非你有一个具体的例子,说明它是有意义的don't do it.
  3. 你的客户是don't need to verify the signature of a JWS token to check expiration人.(除非你加密声明,也就是使用JWE,在这种情况下,你需要做类似的事情,因为你需要一个密钥来解密声明).
  4. 您也不需要验证JWS的签名来判断服务器中的过期情况,但您应该这样做,因为这可以确保没有人更改过期情况(否则验证将失败,因为如果声明发生更改,则重新计算的签名将不同)
  5. 要阅读未加密的声明,只需解码即可.你可以在客户端使用jwt-decode.

我现在意识到,在令牌过期之后,我的前端仍将允许用户请求我的api端点[…]

所以为了实现这个逻辑,我想我需要在客户端验证JWT令牌

如果我没弄错的话,你说的是判断客户端的JWS是否过期.

还有,所有的claims are optional人.

因此,您可以在不验证签名的情况下判断JWT是否过期,因此您既不需要公钥(对于RSA等非对称加密),也不需要密钥(对于AES等对称加密).

jjwt library美元的钞票

JWT可以是加密的signed(JWS)或encrypted(JWE).

Hereligthweigth library from auth0 to decode the base64encoded claims of a JWT/JWS token.

我不知道您为什么认为应该在客户端执行此控制,唯一的优点是避免发送客户端知道会失败的API请求.它们应该会失败,因为服务器应该验证令牌没有过期,之前的签名验证(使用秘密/私钥)显然是无效的.

RFC 7519人对这一说法表示:

"exp"(过期时间)声明标识

在像您所说的那样的web应用中,令牌的使用是为了允许无状态服务器对客户端请求进行身份验证.

如果没有过期,令牌将永远有效,或者直到用于签名的密钥更改(这将导致验证过程失败).

如果我们在用于授权的JWS有效负载(又名声明)中包含信息,例如用户拥有哪些角色,那么会话失效就会成为一个真正的问题.

Stop using JWT for sessions

但更严重的是,这也可能意味着某人拥有一个具有管理员角色的令牌,即使你刚刚撤销了他们的管理员角色.因为您也不能使令牌无效,所以您无法删除它们的管理员访问权限

过期控制并不能解决这个问题,我认为它更倾向于避免会话劫持或CSRF攻击.

使用CSRF的攻击者将能够使用过期的JWS向API发出请求,从而跳过过期控制.

使用公钥验证客户机中的签名或密钥是不同的问题.

关于你的问题

我正在使用的函数似乎需要公钥才能使用它的verify()函数.我似乎没有公钥,只有一个秘密,这是我编造的,所以它不是用一对密钥生成的.

您指出的验证方法明确表示它接受公钥或密钥.

jwt.verify(token, secretOrPublicKey, [options, callback])

secretOrPublicKey是一个字符串或缓冲区,其中包含HMAC算法的密钥,或者包含RSA和ECDSA的PEM编码公钥

我假设你两个都不使用,而且你使用的是像"shhh"这样的字符串.

var token = jwt.sign({ data: '¿Donde esta Santiago?'}, 'shhhh');

那你应该这么做

var decoded = jwt.verify(token, 'shhhhh');

然而,这里的问题是:真的需要客户端签名验证吗?

我认为不是,至少不是针对这种应用程序,客户机只是使用JWS向服务器发送后续请求,并说:"嘿,服务器,我是Gabriel,我这里有一份文件(令牌),可以确保该文件由您签名."

现在,客户端验证需要发送公钥或密钥.

发送密钥(如"shhhh")可能代表一个安全问题,因为密钥与用于签名令牌的密钥相同.

Typescript相关问答推荐

如何将函数类型应用到生成器?

实现忽略了JSSOM中的doctor.body.innerHTML集

根据另一个成员推断类成员的类型

如何在TypeScript对象迭代中根据键推断值类型?

有没有可能使用redux工具包的中间件同时监听状态的变化和操作

在将对象从一个对象转换成另一个对象时,可以缩小对象的键吗?

我们过go 不能从TypeScript中的联合中同时访问所有属性?

具有泛型类方法的类方法修饰符

通过字符串索引访问对象';S的值时出现文字脚本错误

对未到达受保护路由的路由环境做出react

类型脚本映射类型:从对象和字符串列表到键值对象

在类型脚本中创建泛型类型以动态追加属性后缀

重载函数的T helper参数

Angular 自定义验证控件未获得表单值

在Cypress中,是否可以在不标识错误的情况下对元素调用.Click()方法?

抽象类对派生类强制不同的构造函数签名

打印脚本中正则函数和函数表达式的不同类型缩小行为

Typescript不允许在数组中使用联合类型

React Context TypeScript错误:属性';firstName';在类型';iCards|iSearch';

基于参数的 TS 返回类型