0

我正在使用 Webpack5 的客户端 Web 应用程序中实现 JWT 验证。当在运行 PHP 的后端创建用户时,我创建了一个公钥和私钥对,以便在 JWT 中使用,如下所示并存储它们:

$keyPair = sodium_crypto_sign_keypair();
$privateKey = base64_encode(sodium_crypto_sign_secretkey($keyPair));
$publicKey = base64_encode(sodium_crypto_sign_publickey($keyPair));

然后firebase/php-jwt像这样创建请求:

$jwt = JWT::encode($payload, $privateKey, 'EdDSA');

但是,使用jose我在尝试验证 JWT 时收到以下错误:

import * as jose from 'jose';
const { payload, protectedHeader } = await jose.jwtVerify(response.token, window.atob(response.key));
console.log(payload);
console.log(protectedHeader);

TypeError: Key must be of type CryptoKey.

我不明白它如何想要密钥,因为 publicKey 的 base64 字符串和 base64 表示在节点中遇到了相同的 TypeError。我在这里做错了什么?

4

1 回答 1

1

WebCryptography API 不支持 Edwards-Curve 数字签名算法(JOSE 中的 EdDSA),因此使用本机浏览器加密的任何库都不会成功。可悲的是。

有一个提议将 Ed25519、Ed448、X25519 和 X448 添加到 WebCrypto 中,但在采用和实施之前需要一段时间。发生这种情况时jose将支持此操作。话虽如此,您需要传递一个 CryptoKey。可以通过 crypto.subtle.importKey 直接导入,也可以通过jose's import key 函数导入。SubtleCrypto 支持原始公钥导入,jose仅在其包装器中支持 PEM 密钥导入。

有关浏览器算法支持矩阵,请参阅Browser Support,以及有关算法密钥要求的Algorithm Key Requirements,以及有关如何获得正确的密钥表示的Type alias: KeyLike 。

至于其他(现已删除)的建议,他们没有考虑到您使用的算法,建议使用 Uint8Array 而不是 CryptoKey 是错误的, Uint8Array 使用是对称算法独有的。同样,使用 transpiledjsonwebtoken仅对于基于 HMAC 的算法是远程可靠的。

jose仅使用运行时的本机加密层,这是您在一致性和安全实现方面的最佳选择,但在运行跨运行时时,您需要考虑平台上支持的算法的交集。

我不明白它如何想要密钥,因为 publicKey 的 base64 字符串和 base64 表示在节点中遇到相同的 TypeError

它应该是 KeyLike(接口)——在 Node 中是 KeyObject(参见加密文档),在类似 Web 的环境中它是 CryptoKey(参见 WebCryptoAPI)。

于 2022-01-03T07:04:02.600 回答