typescript JWT 验证客户端?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43788131/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 04:30:30  来源:igfitidea点击:

JWT Verify client-side?

node.jstypescriptjwtpassport.jsjson-web-token

提问by George Edwards

I have a nodejs api with an angular frontend. The API is successfully using JWT with passport to secure it's endpoints.

我有一个带有角度前端的 nodejs api。API 成功地使用 JWT 和护照来保护它的端点。

I am now conscious that after the tokens have expired, my front end will still allow the user to request my api endpoints without prompting them to reenter their log in details to get a fresh token.

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

This is how my backend generates the token:

这是我的后端生成令牌的方式:

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

So to implement this logic I think I need to verify the JWT token client-side. Q1, is this a sensible approach.

所以为了实现这个逻辑,我想我需要验证 JWT 令牌客户端。Q1,这是一个明智的方法。

Q2, the JWTlibrary I am using seems to require a public key to use it's verify()function. I don't seem to have a public key, only a secret, which I just made up, so it wasn't generated with a pair. Where does my public key come from, or is there another way of verifying my token without this?

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

This all seems like it should be obvious and that I have missed something, so apologies if this is a stupid question, but I can't seem to find the answer?

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

回答by gabrielgiussi

TL;DR

TL; 博士

  1. You must verifythe signature of JWS in the server always.
  2. Client-side signature verificationdoesn't gives much, unless you have a specific case where it makes sense don't do it.
  3. You don't need to verify the signature of a JWS token to check expirationin the client. (unless you were encrypting the claims, aka using JWE, in that case you need to do something similar because you need a key to decrypt the claims).
  4. You don't need to verify the signature of a JWS to check expiration in the server neither, but you should because this gives you the certainty that nobody has altered the expiration (otherwise the verification will fail because if the claims change then the recalculated signature will differ)
  5. To read non encrypted claims you just only need to decode them. You could use jwt-decodein the client.
  1. 您必须始终服务器中验证JWS 的签名。
  2. 客户端签名验证并没有提供太多,除非您有一个有意义的特定案例,否则不要这样做
  3. 不需要验证 JWS 令牌的签名来检查客户端中的过期时间。(除非您正在加密声明,也就是使用 JWE,在这种情况下您需要做类似的事情,因为您需要一个密钥来解密声明)。
  4. 您不需要验证 JWS 的签名来检查服务器中的过期时间,但您应该这样做,因为这可以让您确定没有人更改过期时间(否则验证将失败,因为如果声明更改,则重新计算签名会有所不同)
  5. 要阅读非加密声明,您只需要对其进行解码。您可以在客户端使用jwt-decode

I am now conscious that after the tokens have expired, my front end will still allow the user to request my api endpoints [...]

So to implement this logic I think I need to verify the JWT token client-side

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

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

If I understood you correctly you are talking about checking if a JWS has expired in the client side. In order to do this you don't need to verify the token signature (although the library you are using seems to be doing both things at the same timefor you, but also lets you to disable expiration control with ignoreExpirationflag). (Unless you're encrypting the claims, aka using JWE) The RFC 7515 (JWS)says nothing about expiration. Message Signature or MAC Validationdoesn't control expiration (and it shouldn't because signatures gives you authenticity and integrity). Even the RFC 7519 (JWT)doesn't control the expiration claim for resolve if a JWT is valid or not.

如果我理解正确,您正在谈论检查客户端的 JWS 是否已过期。为此,您不需要验证令牌签名(尽管您使用的库似乎同时为您做这两件事,但也允许您使用ignoreExpiration标志禁用过期控制)。(除非您对声明进行加密,也就是使用 JWE)RFC 7515 (JWS)没有说明过期。消息签名或 MAC 验证不控制过期(它不应该控制,因为签名为您提供真实性和完整性)。如果 JWT有效与否,即使RFC 7519 (JWT)也不控制解析的到期声明。

Also, all the claims are optional.

此外,所有声明都是可选的

So, you could check if a JWT has expired or not without verifying the signature, hence you don't need neither a public key (for asymmetric encryption like RSA) or a secret key (for symmetric encryption like AES). In JWT and JWS tokens, the claims are just plaintext base64 encoded so you could just decode the payload without verifying if the signature is validand read the expiration claim. If you are encrypting the payload (aka using JWE) then you will not be able to do this.

因此,您可以在不验证签名的情况下检查 JWT 是否已过期,因此您既不需要公钥(对于像 RSA 这样的非对称加密)也不需要密钥(对于像 AES 这样的对称加密)。在 JWT 和 JWS 令牌中,声明只是纯文本 base64 编码,因此您可以只解码有效负载,而无需验证签名是否有效并读取过期声明。如果您正在加密有效负载(也就是使用 JWE),那么您将无法执行此操作。

A note from jjwt library

来自jjwt 库的注释

JWTs can be cryptographically signed(making it a JWS) or encrypted(making it a JWE).

JWT 可以加密签名(使其成为JWS)或加密(使其成为JWE)。

Hereis a ligthweigth library from auth0 to decode the base64encoded claims of a JWT/JWS token. A guy is even asking about checking expiration.

来自 auth0ligthweigth 库,用于解码 JWT/JWS 令牌的 base64encoded 声明。一个人甚至在询问检查过期时间

I don't know why you think that you should be doing this control client-side, the only advantage is avoiding sending API request that the client knows that will fail. And they should fail because the server should be validating that the token hasn't expired, previous signature verification (with secret/private key) obviously.

我不知道你为什么认为你应该在客户端做这个控制,唯一的好处是避免发送客户端知道会失败的 API 请求。并且它们应该失败,因为服务器应该验证令牌尚未过期,显然先前的签名验证(使用秘密/私钥)。

The RFC 7519says about this claim:

RFC 7519说,这个要求:

The "exp" (expiration time) claim identifies the expiration time on or after which the JWT MUST NOT be accepted for processing.

“exp”(过期时间)声明标识了 JWT不得被接受处理的过期时间或之后的过期时间。

In a web app like the one you say the use of tokens is to allow stateless servers to authenticate client requests. The goal of the OPTIONALexpiration claim is to allow the server have some control over the generated JWS (if we are using JWT for authentication signing them is a must so we should be talking about JWS).

在像您所说的那样的 Web 应用程序中,使用令牌是为了允许无状态服务器对客户端请求进行身份验证。OPTIONAL过期声明的目标是允许服务器对生成的 JWS 有一定的控制权(如果我们使用 JWT 进行身份验证,则必须对它们进行签名,所以我们应该谈论 JWS)。

Without expiration, the tokens will be valid forever or until the key used to signing them change (this will make the verification process to fail). By the way, invalidatingsessionsis one of the most notorious disadvantages of using stateless authentication.

如果没有过期,令牌将永远有效或直到用于签署它们的密钥发生变化(这将使验证过程失败)。顺便说一下,使会话无效是使用无状态身份验证最臭名昭著的缺点之一。

Session invalidation becomes a real problem if we are including information in the JWS payload (aka claims) used for authorization, for example which roles the user have.

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

From Stop using JWT for sessions

停止使用 JWT 进行会话

but more seriously, it can also mean somebody has a token with a role of admin, even though you've just revoked their admin role. Because you can't invalidate tokens either, there's no way for you to remove their administrator access

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

The expiration control doesn't solve this problem and I think is more oriented to avoid session hiHymaning or CSRF attacks.

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

An attacker using CSRF will be able to make a request with an expired JWS to your API skipping the expiration control.

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

A different issue is verifying the signature in the client using the public or secret key.

另一个问题是使用公钥或私钥验证客户端中的签名。

Regarding your question

关于你的问题

I am using seems to require a public key to use it's verify() function. I don't seem to have a public key, only a secret, which I just made up, so it wasn't generated with a pair.

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

The verify method you pointed out says explicitlly that it accepts a public or secret key.

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

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

secretOrPublicKey is a string or buffer containing either the secret for HMAC algorithms, or the PEM encoded public key for RSA and ECDSA

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

I assume you are using neither and you are using a string like 'shhhh'.

我假设您既不使用,又使用像“shhhh”这样的字符串。

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

Then you should do

那你应该做

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

However, the question here is: Is client-side signature verification really needed?

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

I think is not, at least not for this kind of application where the client just uses the JWS to send subsequent request to the server saying: "Hey server, I'm Gabriel and I have a paper (token) here that assures that and that paper is signed by you." So if the client doesn't validate the JWS and a MITM had successfully gave to that client a JWS signed by himself (instead to the JWS signed by the server), then the subsequent request will simply fail. Like expiration control, signature verification only prevent the client to make request that will fail.

我认为不是,至少对于这种客户端仅使用 JWS 向服务器发送后续请求的应用程序来说不是这样:“嘿,服务器,我是 Gabriel,我在这里有一张纸(令牌),可以确保和那张纸上有你的签名。” 因此,如果客户端不验证 JWS 并且 MITM 已成功向该客户端提供了一个由他自己签名的 JWS(而不是由服务器签名的 JWS),那么后续请求将简单地失败。与过期控制一样,签名验证仅防止客户端发出将失败的请求。

Now, client side verification requires sending the public or secret key. Sending public key doesn't represent a security concern but it's extra effort and processing with little benefits.

现在,客户端验证需要发送公钥或私钥。发送公钥并不代表安全问题,但它是额外的努力和处理,几乎没有好处。

Sending secret keys (like 'shhhh') can represent a security issue because is the same key that is used to sign tokens.

发送密钥(如“shhhh”)可能代表安全问题,因为用于签署令牌的密钥相同。

回答by ugursogukpinar

I think verifying JWT token at client-side is not a good idea.
IMO;

我认为在客户端验证 JWT 令牌不是一个好主意。
海事组织;

  1. Whenever a user logs in, generate access and refresh token and return to user something like this;

    { "accessToken": <<accessToken>> "refreshToken": <<refreshToken>> "expiresAt": <<expiresAt>> }

    So client can understand when access token expire and can refresh it with refresh token.

  2. Encrypt the data that you put in the access token because there is a chance to access the data without secret key. But of course someone needs to secret key to verify.

  1. 每当用户登录时,生成访问和刷新令牌并返回给用户这样的东西;

    { "accessToken": <<accessToken>> "refreshToken": <<refreshToken>> "expiresAt": <<expiresAt>> }

    因此客户端可以了解访问令牌何时到期并可以使用刷新令牌刷新它。

  2. 加密您放入访问令牌中的数据,因为有机会在没有密钥的情况下访问数据。但是当然有人需要秘密密钥来验证。

回答by Dmytro

Q1:Token verification on client is a bad idea. What you can do is to save a token together with a same expired date on client and then refresh/remove a token. But my thought that it is better to have some date checkig on server side cause exist simple rule: Don't trust the clientcause it can always send malicious code.

Q1:客户端上的令牌验证是一个坏主意。您可以做的是在客户端上将令牌与相同的过期日期一起保存,然后刷新/删除令牌。但我认为最好在服务器端进行一些日期检查,因为存在简单的规则:不要相信客户端,因为它总是可以发送恶意代码。

Q2:JWT don't need any public key. It always must have private key storing on server side cause if someone known your secret key your token don't make any sense. You only can add some payload to do it more complex.

Q2:JWT 不需要任何公钥。它始终必须在服务器端存储私钥,因为如果有人知道您的密钥,您的令牌就没有任何意义。您只能添加一些有效负载以使其更复杂。

回答by Amulya Kashyap

Answer 1: It is not considered to be a good approach to verify your auth token on the client side as it involves secret key while encoding/decoding it and keeping the secret key on the client side is not secure.

答案 1:在客户端验证您的身份验证令牌不被认为是一种好方法,因为它在编码/解码时涉及密钥并且将密钥保存在客户端是不安全的

Creating Token

创建令牌

jwt.sign({ data: 'foobar' }, 'secret', { expiresIn: 60 * 60 });

jwt.sign({ data: 'foobar' }, 'secret', { expiresIn: 60 * 60 });

Verifying Token

验证令牌

jwt.verify(token, 'secret', function(err, decoded) { console.log(decoded.foo) // bar });

jwt.verify(token, 'secret', function(err, decoded) { console.log(decoded.foo) // bar });

Answer 2: JWT involves secretORPublic key while encoding and decoding token. It has to be declared or kept in the config file somewhere on the server side.

答案 2:JWT在编码和解码令牌时涉及秘密公钥。它必须在服务器端某处的配置文件中声明或保存。

Explanation: Decoding means decoding from Base64, there's no secret key involved in that process. On the other hand, verifying a JWT would require a secret key because it would involve a cryptographic signature operation.

To sum up, decoding does not need the secret (remember decoding is just interpreting base64) and verifying/signing does require it

说明: 解码就是从Base64解码,这个过程不涉及秘钥。另一方面,验证 JWT 需要一个秘密密钥,因为它涉及加密签名操作。

总而言之,解码不需要秘密(记住解码只是解释 base64)并且验证/签名确实需要它