什么是基于JWT的身份验证的密钥以及如何生成它?

时间:2015-07-09 06:32:19

标签: jwt

最近我开始使用基于JWT的身份验证。用户登录后,会生成一个用户令牌 " eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"

它由三个部分组成,每个部分用点(。)分隔。第一部分是Base64编码的标题。解码后我们会得到类似的东西 {   " alg":" HS256",//使用的算法   " typ":" JWT" }

第二部分是声明和Base64编码。解码后我们会得到类似的东西 {   " sub":" 1234567890",   "姓名":" John Doe",   " admin":是的 }

第三部分是签名,用

生成

HMACSHA256(     base64UrlEncode(header)+"。" +     base64UrlEncode(有效载荷),     秘密base64编码   )

现在这个密钥是什么以及如何生成这个密钥?

我尝试了一些在线生成器,例如" http://kjur.github.io/jsjws/tool_jwt.html" 但是得到很多帮助。

6 个答案:

答案 0 :(得分:32)

Json Web令牌由三部分组成。标头,有效载荷和签名现在,标头只是有关令牌本身的一些元数据,有效载荷是我们可以编码为令牌的数据,也就是我们真正想要的任何数据。因此,我们要在此处编码的数据越多,JWT越大。无论如何,这两个部分只是纯文本,将被编码,但不会被加密。

因此任何人都可以对其进行解码和读取,我们无法在此处存储任何敏感数据。但这根本不是问题,因为在签名的第三部分中,事情确实变得很有趣。签名是使用标头,有效负载和服务器上保存的机密创建的。

然后将整个过程称为签署Json Web令牌。签名算法采用标头,有效负载和秘密来创建唯一的签名。所以只有这些数据加上秘密才能创建此签名,好吗? 然后,这些签名连同标头和有效负载一起组成JWT, 然后将其发送给客户端。 enter image description here

一旦服务器接收到JWT来授予对受保护路由的访问权,它就需要对其进行验证,以确定用户是否确实是他声称的身份。换句话说,它将验证是否没有人更改令牌的标头和有效载荷数据。同样,此验证步骤将检查是否没有第三方实际更改Json Web令牌的标头或有效载荷。

那么,此验证实际上如何工作?好吧,这实际上很简单。收到JWT后,验证将获取其标头和有效负载,以及仍保存在服务器上的机密信息,基本上会创建一个测试签名。

但是第一次创建JWT时生成的原始签名仍然在令牌中,对吗?这就是验证的关键。因为现在我们要做的就是将测试签名与原始签名进行比较。 并且,如果测试签名与原始签名相同,则表示有效负载和标头尚未修改。 enter image description here

因为它们已经被修改,所以测试签名必须是不同的。因此,在这种情况下,数据没有发生变化,我们可以对用户进行身份验证。当然,如果两个签名 实际上是不同的,那么,这意味着有人篡改了数据。 通常通过尝试更改有效负载。但是,操纵有效载荷的第三方当然不能访问该秘密,因此它们无法签署JWT。 因此,原始签名将永远不会对应于被操纵的数据。 因此,在这种情况下,验证将始终失败。这是使整个系统正常工作的关键。是让JWT变得如此简单的魔力, 但也非常强大。

现在让我们对nodejs进行一些实践:

配置文件非常适合存储JWT SECRET数据。使用标准的HSA 256加密进行签名,密钥长度至少应为32个字符,但越长越好。

config.env:

JWT_SECRET = my-32-character-ultra-secure-and-ultra-long-secret
//after 90days JWT will no longer be valid, even the signuter is correct and everything is matched.
JWT_EXPIRES_IN=90

现在使用命令安装JWT

npm i jsonwebtoken

用户注册后为其传递JWT令牌,以便他可以保持登录状态并获得资源访问权限的示例。

exports.signup = catchAsync(async (req, res, next) => {
  const newUser = await User.create({
    name: req.body.name,
    email: req.body.email,
    password: req.body.password,
    passwordConfirm: req.body.passwordConfirm,
  });
  const token = jwt.sign({ id: newUser._id }, process.env.JWT_SECRET, {
    expiresIn: process.env.JWT_EXPIRES_IN,
  });

  res.status(201).json({
    status: 'success',
    token,
    data: {
      newUser,
    },
  });
});

输出: enter image description here

我认为,请勿寻求第三方的帮助来生成您的超级秘密密钥,因为您不能再说它是秘密了。只需使用键盘即可。

答案 1 :(得分:25)

用于签署JWT的算法(HS256)意味着该秘密是发送方和接收方都知道的对称密钥。它是在带外协商和分发的。因此,如果您是令牌的预期收件人,则发件人应该已向您提供带外秘密。

如果你是发件人,你可以使用任意字节串作为秘密,可以生成或故意选择。您必须确保向带外的目标收件人提供秘密。

对于记录,JWT中的3个元素不是base64编码的,而是base64url编码的,它是base64编码的变体,可以产生URL安全值。

答案 2 :(得分:6)

您可以编写自己的发电机。密钥本质上是一个字节数组。确保转换为字节数组的字符串是base64编码的。 在Java中你可以做这样的事情。

String key = "random_secret_key";
String base64Key = DatatypeConverter.printBase64Binary(key.getBytes());
byte[] secretBytes = DatatypeConverter.parseBase64Binary(base64Key);

答案 3 :(得分:0)

什么是秘密密钥

密钥与标头和有效载荷结合在一起以创建唯一的哈希。只有拥有密钥,您才能验证此哈希。

如何生成密钥

您可以选择一个好的长密码。或者您可以从this之类的网站生成它。

示例(但现在不要使用此示例):

8Zz5tw0Ionm3XPZZfN0NOml3z9FMfmpgXwovR9fp6ryDIoGRM8EPHAB6iHsc0fb

答案 4 :(得分:0)

密钥到底是做什么的,您到目前为止可能已经知道。 它基本上是HMAC SH256(安全哈希)。 秘密是对称密钥。

使用您可以生成,重新验证,编辑等相同的密钥。

为了更加安全,您可以使用私钥,公钥(非对称方式)。 用于创建令牌的专用密钥,用于在客户端级别进行验证的公用密钥。

使用密钥该给什么 您可以输入任何长度的“ sudsif”,“ sdfn2173”

您可以使用在线生成器,也可以手动编写

我更喜欢使用openssl

C:\Users\xyz\Desktop>openssl rand -base64 12
65JymYzDDqqLW8Eg

生成,然后以64为底进行编码

C:\Users\xyz\Desktop>openssl rand -out openssl-secret.txt -hex 20

生成的值保存在名为“ openssl-secret.txt”的文件中

生成并存储到文件中。

一件事情是给12将只生成12个字符,但是由于它是以64为基数编码的,因此它将是(4/3 * n)个上限值。

我建议阅读这篇文章

https://auth0.com/blog/brute-forcing-hs256-is-possible-the-importance-of-using-strong-keys-to-sign-jwts/

答案 5 :(得分:0)

如果您正在寻找 JWT_AUTH_SECRET_KEY 的密钥,那么您可以使用此处生成的任何密钥:

https://api.wordpress.org/secret-key/1.1/salt/

这通常用于“WP REST API 的 JWT 身份验证” ( https://wordpress.org/plugins/jwt-authentication-for-wp-rest-api/ )

也许你是像我一样来到这里寻找那个的人:D