2017-05-04 118 views
2

我有一个有角度前端的nodejs api。该API成功使用JWT和护照来保护其端点。智威汤逊验证客户端?

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

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

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

因此,要实现这个逻辑,我想我需要验证令牌JWT的客户端。 Q1,这是一个明智的做法。

Q2,我使用的JWT库似乎需要一个公钥才能使用它的verify()函数。我似乎没有公钥,只有一个秘密,我只是编了一个秘密,所以它不是用一对产生的。我的公钥来自哪里,或者有没有另外一种验证我的令牌的方式?

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

回答

0

答1:它不认为是一个很好的方法来验证客户端的身份验证令牌,因为它涉及秘密密钥而编码/解码,并保持在客户端密钥是不安全

创建令牌

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

验证令牌

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

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

说明: 解码指从Base64编码解码,还有参与这一过程中没有密钥。另一方面,验证智威汤逊将需要一个秘密密钥,因为它会涉及加密签名操作。

综上所述,解码不需要秘密(记得解码只是解释的base64)和验证/签名确实需要它

0

我想验证JWT令牌在客户端是不是好主意。 IMO;

1-每当用户登录时生成访问并刷新令牌并返回给用户那样;

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

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

2-加密您放入访问令牌的数据,因为有机会访问没有密钥的数据。但是有人需要密钥来验证。

0

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

Q2:智威汤逊不需要任何公钥。它总是必须有私钥存储在服务器端,如果有人知道你的秘密密钥,你的令牌没有任何意义。您只能添加一些有效载荷,使其更加复杂。

4

TL; DR

  1. 您必须验证 JWS在服务器始终签名。
  2. 客户端签名验证并没有给出太多,除非你有一个特定的情况下有意义不要这样做
  3. 不需要验证JWS令牌的签名来检查客户端中的到期。 (除非你是在加密声明,也就是使用JWE,在这种情况下你需要做类似的事情,因为你需要一个密钥来解密声明)。
  4. 您不需要验证JWS的签名以检查服务器中的到期日期,但是您应该这样做,因为这样可以确保没有人更改过期日期(否则验证将失败,因为如果索赔更改,则重新计算的签名将有所不同)
  5. 要读取非加密声明,您只需要解码它们即可。您可以在客户端使用jwt-decode

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

因此,要实现这个逻辑我想我需要验证JWT令牌客户端

如果我正确理解您,您正在讨论检查JWS是否已在客户端过期。 为了做到这一点,您不需要验证令牌签名(尽管您正在使用的库似乎正在为您做both things at the same time,但也可以让您使用ignoreExpiration标志禁用到期控制)。 (除非您正在加密声明,也就是使用JWE) RFC 7515 (JWS)没有提到过期。Message Signature or MAC Validation不控制到期(并且不应该因为签名给你真实性和完整性)。 即使RFC 7519 (JWT)也不能控制如果JWT is valid or not已解决的到期索赔。

另外,所有的claims are optional。因此,您可以检查JWT是否已过期或未验证签名,因此既不需要公共密钥(用于RSA等非对称加密),也不需要用于对称加密(如AES)的密钥(既不需要公钥也不需要)。 在JWT和JWS令牌中,声明只是明文base64编码,因此您只需decode the payload without verifying if the signature is valid并阅读到期声明。 如果你正在加密有效载荷(又名使用JWE),那么你将无法做到这一点。

的说明从jjwt library

JWTs可以是加密签署(使其成为一个JWS)或加密(使其成为一个JWE)。

Here是从auth0一个ligthweigth库以JWT/JWS的base64encoded声明令牌解码。 一个男人甚至问起checking expiration

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

RFC 7519说了解这个要求:

的“EXP”(到期时间)根据权利要求标识过期时间上 或在此之后,JWT 必须不用于处理被接受。

在一个Web应用程序中,您说的令牌的使用是允许无状态服务器对客户端请求进行身份验证。 可选到期声明的目标是允许服务器对生成的JWS进行一些控制(如果我们使用JWT进行身份验证,则必须签署它们,因此我们应该谈论JWS)。

没有到期,令牌将永久生效或直到用于签名的密钥更改(这将使验证过程失败)。 顺便说一下,invalidatingsessions是使用无状态身份验证最臭名昭着的缺点之一。

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

Stop using JWT for sessions

,但更严重的是,它也可以指人与管理员的角色令牌,即使你只是吊销了其管理角色。因为你也不能无效令牌,有没有办法为你免除他们的管理员权限

到期控制的不解决这个问题,我认为是更注重以避免会话劫持或CSRF攻击。

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

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

关于你的问题

我使用似乎都需要一个公共密钥使用它来验证()函数。我似乎没有公钥,只有一个秘密,我只是编了一个秘密,所以它不是用一对产生的。

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

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

secretOrPublicKey是RSA和ECDSA

字符串或它可以包含HMAC算法的秘密,或PEM缓冲编码的公共密钥我假设你既没有使用,你使用的是像'shhhh'字符串。

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

那么你应该做的

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

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

我想不是,至少不是这种类型的应用程序,其中客户端只是使用JWS发送后续请求到服务器说:“嘿服务器,我是加百列,我在这里有一个纸张(令牌)这可以保证你的文件是由你签署的。“ 因此,如果客户端不验证JWS并且MITM已成功向该客户端发送了由他自己签名的JWS(而不是由服务器签名的JWS),则后续请求将会失败。 像到期控制一样,签名验证只能防止客户端发出失败的请求。

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

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