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

最近我开始使用基于 JWT 的身份验证

"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ".

它由三部分组成,每部分用一个点分开.第一部分是头部 Base64编码。解码后,我们会得到类似

{
"alg": "HS256", //Algorithm used
"typ": "JWT"
}

第二部分是声明和 Base64编码。解码后,我们将得到类似

{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}

第三部分是签名,使用

HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
*secret base64 encoded*
)

这个密钥是什么? 如何生成这个密钥?

我试过一些像 http://kjur.github.io/jsjws/tool_jwt.html这样的在线发电机 但没有得到多少帮助。

267370 次浏览

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

如果您是发送方,您可以使用任意字节字符串作为秘密,它可以被生成或有目的地选择。你必须确保你提供的秘密,以预期收件人乐队以外。

对于记录,JWT 中的3个元素不是 base64编码的,而是 base64url 编码的,这是 base64编码的一个变体,其结果是 URL 安全值。

您可以编写自己的生成器。密钥本质上是一个字节数组。确保转换为字节数组的字符串是 base64编码的。

在 Java 中,你可以这样做。

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

秘密钥匙是什么

秘密密钥与报头和有效负载组合在一起,以创建唯一的散列。只有在拥有秘密密钥的情况下,才能验证此哈希值。

如何生成密钥

您可以选择一个好的、长的密码。或者您可以从像 这个这样的站点生成它。

例子(但是现在不要用这个例子) :

8Zz5tw0Ionm3XPZZfN0NOml3z9FMfmpgXwovR9fp6ryDIoGRM8EPHAB6iHsc0fb

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

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

这整个过程被称为 签署 Json Web 令牌。签名算法接受标头、有效负载和秘密来创建唯一签名。只有这些数据加上秘密才能创造这个签名,好吗? 然后,这些签名与报头和有效负载一起构成 JWT, 然后发送给客户端。 enter image description here

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

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

但是最初创建 JWT 时生成的原始签名仍然在令牌中,对吗?这就是验证的关键。因为现在我们要做的就是比较测试签名和原始签名。 如果测试签名与原始签名相同,那么这意味着有效负载和报头没有被修改。 enter image description here

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

现在让我们对 nodejs 进行一些练习:

配置文件非常适合存储 JWT 保密数据。使用标准的 HSA 256加密签名,秘密应该至少有32个字符长,但越长越好。

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

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

秘密钥匙是做什么的,你可能已经知道到现在。 它基本上是 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/

如果您正在寻找 JWT _ AUTH _ Secret _ KEY 的密钥,那么您可以使用这里生成的任何密钥:

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

这通常适用于“ JWT Authentication for WP REST API” (https://wordpress.org/plugins/jwt-authentication-for-wp-rest-api/)

也许你就是像我一样来这里寻找的人

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

crypto.randomBytes(64).toString("hex");