当前位置: 首页 > 知识库问答 >
问题:

试图在nodejs中验证JWT签名,以了解JWT的内部工作,但解密签名给出了错误的值

严玉泽
2023-03-14

为了理解数字签名和JWT是如何工作的,我尝试使用RS256算法验证JSON网络令牌。但是,当我解密JWT的签名部分时,它会给出非字符串值,因此我无法将该值与计算出的哈希值进行比较。有人能告诉我我在代码中误解了什么吗?我使用了RS256算法JWT令牌,所有的值都在https://jwt.io/.中给出。如果您向下滚动并选择RS256选项,您可以获得bas64url编码的JWT和公共/私钥。我想我解密了JWT的错误部分,但找不到。

const base64url = require('base64url')
const crypto = require('crypto')
const fs = require('fs')

function readKeyPair(path) {
    return {
        publicKey: fs.readFileSync(path.publicPath),
        privateKey: fs.readFileSync(path.privatePath)
    }
}

function encryptWithPrivateKey(privateKey, message) {
    const bufferMessage = Buffer.from(message, 'utf8');
    return crypto.privateEncrypt(privateKey, bufferMessage)
}

function decryptWithPublicKey(publicKey, buffer) {
    return crypto.publicDecrypt(publicKey, buffer);
}

function hashMessage(message, algorithm) {
    const hash = crypto.createHash(algorithm);
    hash.update(message);
    const hashValue = hash.digest('hex')
    return hashValue;
}

const JWT = (
    'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZS' +
    'I6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.POstGetfAytaZ' +
    'S82wHcjoTyoqhMyxXiWdR7Nn7A29DNSl0EiXLdwJ6xC6AfgZWF1bOsS_TuYI3OG85AmiExR' +
    'EkrS6tDfTQ2B3WXlrr-wp5AokiRbz3_oB4OxG-W9KcEEbDRcZc0nH3L7LzYptiy1PtAylQG' +
    'xHTWZXtGz4ht0bAecBgmpdgXMguEIcoqPJ1n3pIWk_dUZegpqx0Lka21H6XxUTxiy8Ocaar' +
    'A8zdnPUnV6AmNP3ecFawIFYdvJB_cm-GvpCSbr8G8y_Mllj8f4x9nBH8pQux89_6gUY618i' +
    'Yv7tuPWBFfEbLxtF2pZS6YC1aSfLQxeNe8djT9YjpvRZA'
)

const KEY_PAIR_PATH = {
    publicPath: 'rsa_pub.pem',
    privatePath: 'rsa_priv.pem'
}

const jwtParts = JWT.split('.')
const header = base64url.decode(jwtParts[0])
const payload = base64url.decode(jwtParts[1])
const signature = base64url.toBuffer(jwtParts[2])

console.log(header)
console.log(payload)
console.log(signature)

const keyPair = readKeyPair(KEY_PAIR_PATH)
const decryptedHashValue = decryptWithPublicKey(keyPair.publicKey, signature);

const newHash = hashMessage(jwtParts[0] + '.' + jwtParts[1], 'SHA256')
console.log()
console.log(decryptedHashValue.toString())
console.log()
console.log(newHash)

这是代码的输出

{"alg":"RS256","typ":"JWT"}
{"sub":"1234567890","name":"John Doe","admin":true,"iat":1516239022}
<Buffer 3c eb 2d 19 eb 5f 03 2b 5a 65 2f 36 c0 77 23 a1 3c a8 aa 13 32 c5 78 96 75 1e cd 9f b0 36 f4 33 52 97 41 22 5c b7 70 27 ac 42 e8 07 e0 65 61 75 6c eb ... 206 more bytes>

010     `�He �A����O��H7��Rb�'��!9���Ct�_S

8041fb8cba9e4f8cc1483790b05262841f27fdcb211bc039ddf8864374db5f53

共有1个答案

辛弘壮
2023-03-14

发布的代码UTF8对decryptedHashValue的值进行解码,从而破坏数据并产生胡言乱语。必须使用二进制到文本编码(如Base64或十六进制编码)将任意二进制数据(如密文或哈希值)转换为字符串。由于hashMessage()hex对数据进行编码,因此在这里选择十六进制编码是合适的:

console.log(decryptedHashValue.toString('hex'))

它提供以下输出:

3031300d0609608648016503040201050004208041fb8cba9e4f8cc1483790b05262841f27fdcb211bc039ddf8864374db5f53

此值可以分为以下两部分:

3031300d060960864801650304020105000420

8041fb8cba9e4f8cc1483790b05262841f27fdcb211bc039ddf8864374db5f53

第二部分正好对应于用newHash()确定的哈希值newHash。第一部分对应于SHA-256的摘要ID,该ID在PKCS1 v1的情况下是预先添加的。5填充(RSASSA-PKCS1-v1_5,s.RFC8017),由privateEncrypt()publidecrypt()使用的默认填充。

但是,我无法用您发布的代码重现您发布的哈希值。

 类似资料:
  • 我正在JWT(JSON Web令牌)方案的帮助下实现一个登录系统。基本上,在用户登录/登录之后,服务器签署一个JWT并将其传递给客户机。 然后,客户机返回每个请求的令牌,服务器在发送回响应之前验证令牌。 这是你所期望的,但是我在这个过程的逻辑上遇到了一些问题。从我读过的所有数学文章来看,RSA签名似乎使用非对称密钥进行签名。由于公钥(顾名思义)是向客户机公开的,而私钥保留在服务器上,因此使用发送给

  • 使用库"firebase_id_token"验证ruby on rails中的Firebase id令牌。 一旦我用google_sign_in库从前端获得有效令牌并发送到后端,它总是提示“JWT::VerificationError(签名验证引发)”。尽管我已经检查了jwt.io,在那里我可以看到有效载荷和报头的信息,但无法验证签名。 firebase_id_token.rb 另外,我检查了密钥

  • 我目前正在使用Vapor开发Swift后端。我的iOS客户端使用新的iOS 13功能“使用Apple登录”。当用户登录时,我会得到一个身份令牌(访问令牌),这是一个由Apple签名的有效JWT令牌。这将在所有正在进行的通信中发送到服务器,以验证服务器提供的某些路由。 在服务器上,我想通过验证令牌签名来验证发送的令牌是否确实由Apple签名,并且不是由某些恶意用户专门创建的。Apple提供了一个HT

  • 我正在尝试为我的组织实施OpenID Connect规范。我正在一个测试依赖方应用程序中使用微软的OpenID Connect的OWIN实现来验证我的协议实现。 我公开了以下元数据文档: 签名密钥公开为以下文档: 身份令牌是使用类及其关联的处理程序,使用类生成的。此代码代表令牌的构造方式,并将其作为响应数据的参数返回给调用系统。 当我试图将签名的令牌传递回依赖方应用程序时,OWIN中间件接受POS

  • 我正在制作一个javascript客户端,它使用JWT令牌连接到Api。在服务器端没有问题,我可以创建令牌对其进行签名,然后验证签名,从而确保没有人篡改令牌。 但我如何在客户端做到这一点。我可以解码JWT令牌并查看头、负载和签名。但是如何在客户端验证签名?是否有用于此的库,如何将公钥传输到客户端? 如果我不验证签名,我怎么知道令牌没有被篡改?

  • 这就是我面临的问题, https://play.golang.org/p/Pq8xHAERD57 如果运行上述代码,第一个令牌JWKS对不会验证签名,但第二个会验证!但两者都在jwt中验证签名。木卫一。有什么办法可以用一个Golang图书馆来验证它吗? 奇怪的是如果你拿了失败的代币?我调试后发现函数func VerifyPKCS1v15(pub*PublicKey,hash crypto.hash