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

RIP*_*PAN 29 jwt

最近我开始使用基于JWT的身份验证.在用户登录之后,生成用户令牌,其看起来像"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ".

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

第二部分是索赔和Base64编码.解码后,我们会得到类似{"sub":"1234567890","name":"John Doe","admin":true}

第三部分是签名并生成

HMACSHA256(base64UrlEncode(header)+"."+ base64UrlEncode(payload), secret base64编码 )

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

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

Lor*_*ord 88

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

所以任何人都可以解码和阅读它们,我们不能在这里存储任何敏感数据。但这根本不是问题,因为在第三部分,所以在签名中,事情才真正变得有趣。签名是使用标头、有效负载和保存在服务器上的秘密创建的。

然后整个过程称为签署 Json Web Token。签名算法采用标头、有效载荷和秘密来创建唯一的签名。所以只有这些数据加上秘密才能创建这个签名,好吗?然后与标头和有效负载一起,这些签名形成 JWT,然后将其发送到客户端。 在此处输入图片说明

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

那么,这种验证实际上是如何工作的呢?嗯,它实际上很简单。收到 JWT 后,验证将获取其标头和有效载荷,并与仍保存在服务器上的机密一起,基本上创建一个测试签名。

但是最初创建 JWT 时生成的原始签名仍在令牌中,对吗?这就是这个验证的关键。因为现在我们要做的就是将测试签名与原始签名进行比较。如果测试签名与原始签名相同,则说明payload和header没有被修改。 在此处输入图片说明

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

现在让我们用nodejs做一些实践:

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

配置文件:

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
Run Code Online (Sandbox Code Playgroud)

现在使用命令安装 JWT

npm i jsonwebtoken

Run Code Online (Sandbox Code Playgroud)

用户注册后的示例向他传递 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,
    },
  });
});
Run Code Online (Sandbox Code Playgroud)

输出: 在此处输入图片说明

在我看来,不要求助于第三方来生成你的超级密钥,因为你不能再说它是秘密了。只需使用您的键盘。

  • 组织良好的迷你文章。竖起大拇指! (10认同)
  • 在我看来,这是最好的答案。感谢您提供的图片 - 真正说明了这一点! (6认同)
  • 这应该是公认的答案,因为它包含更详细的信息 (5认同)

Sur*_*gch 37

什么是秘钥

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

如何生成密钥

您可以选择一个好的、长的密码。或者你可以从喜欢的网站生成它这个

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

8Zz5tw0Ionm3XPZZfN0NOml3z9FMfmpgXwovR9fp6ryDIoGRM8EPHAB6iHsc0fb
Run Code Online (Sandbox Code Playgroud)

  • 在线生成密码是一个非常非常糟糕的主意:-)只需在本地使用“/dev/urandom”即可:https://unix.stackexchange.com/questions/230673/how-to-generate-a-random-细绳 (23认同)

Han*_* Z. 29

HS256用于对JWT进行签名的算法()意味着该秘密是发送者和接收者都知道的对称密钥.它是在带外协商和分发的.因此,如果您是令牌的预期收件人,发件人应该已经为您提供了带外秘密.

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

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

  • 更具体地说,对称意味着使用相同的密钥来生成和验证签名。对于 Web 应用程序,Web 服务器既是生成器又是验证器。客户端只是存储令牌。在任何情况下,您都不应与任何人共享密钥,尤其是您的网络应用程序的用户。 (2认同)

小智 13

要生成 64 字节的唯一密钥,请在节点中运行以下命令:

crypto.randomBytes(64).toString("hex");
Run Code Online (Sandbox Code Playgroud)


Dan*_*son 12

对于 JWT,常用的签名算法是HMAC SHA256 。对于该算法,32 个字节就足够了

32 字节数组可以表示为 64 个字符长的十六进制字符串,因为 2 个十六进制字符等于 1 个字节。可以使用以下终端命令生成 32 个随机字节(以十六进制字符串表示):

$ openssl rand -hex 32
Run Code Online (Sandbox Code Playgroud)

它输出的示例:

4f1feeca525de4cdb064656007da3edac7895a87ff0ea865693300fb8b6e8f9c
Run Code Online (Sandbox Code Playgroud)

通过使用上面的命令,密钥将在您的计算机上本地生成。使用网站生成密码可能很危险,因此最好在本地进行。

根据您使用的语言,后续步骤可能会有所不同。但在 C# 中,您可以使用以下函数将十六进制字符串转换为字节数组:

4f1feeca525de4cdb064656007da3edac7895a87ff0ea865693300fb8b6e8f9c
Run Code Online (Sandbox Code Playgroud)

在 C# 中,可以通过以下方式生成 JWT 令牌:

public static byte[] FromHexStringToByteArray(string hexString) 
{
    var byteArray = new byte[hexString.Length / 2];
    for (var i = 0; i < hexString.Length; i += 2)
    {
        byteArray[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
    }
    return byteArray;
}
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,密钥采用十六进制字符串的形式,并转换为字节数组。SigningCredentials接下来,使用设置为 HMAC SHA256 的密钥和算法创建 的实例。随后,将使用凭据创建令牌。


sha*_*608 6

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

String key = "random_secret_key";
String base64Key = DatatypeConverter.printBase64Binary(key.getBytes());
byte[] secretBytes = DatatypeConverter.parseBase64Binary(base64Key);
Run Code Online (Sandbox Code Playgroud)


小智 6

如果您正在寻找 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


P S*_*tro 5

秘钥的作用是什么,你可能已经知道了。它基本上是 HMAC SH256(安全哈希)。Secret 是一个对称的密钥。

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

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

来到密钥什么给你你可以给任何东西,“sudsif”,“sdfn2173”,任何长度

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

我更喜欢使用 openssl

C:\Users\xyz\Desktop>openssl rand -base64 12
65JymYzDDqqLW8Eg
Run Code Online (Sandbox Code Playgroud)

生成,然后用 base 64 编码

C:\Users\xyz\Desktop>openssl rand -out openssl-secret.txt -hex 20
Run Code Online (Sandbox Code Playgroud)

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

生成并存储到文件中。

一件事是生成 12 个字符,仅生成 12 个字符,但由于它是 base 64 编码的,因此它将是 (4/3*n) 上限值。

我推荐阅读这篇文章

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

  • 你可以运行 `openssl rand &lt;...args&gt; | Clip` 将其复制到剪贴板而不是写入文件 (3认同)