簡體   English   中英

在 node.js 中驗證 JWT

[英]Validating a JWT in node.js

我正在嘗試基於此示例(在 .NET 中編寫)解析和驗證 node.js 中的 JWT 令牌: https : //github.com/liveservices/LiveSDK/blob/master/Samples/Asp.net/AuthenticationTokenSample/ JsonWebToken.cs

這是我驗證令牌的節點 js javascript:

var validateSignature = function(key, claims, envelope, signature) {
    var hasher = crypto.createHash('sha256');
    hasher.update(key + "JWTSig");
    var key = hasher.digest('binary');
    var hmac = crypto.createHmac('sha256', key);
    hmac.update(envelope + '.' + claims);
    var out = hmac.digest('base64');
    console.log(out);
    console.log(signature);
    console.log(out === signature);
}

現在,非常奇怪的是 - 它幾乎可以工作。 這是三個 console.log 語句的輸出:

pEwNPJ+LUHBdvNx631UzdyVhPFUOvFY8jG3x/cP81FE=
pEwNPJ-LUHBdvNx631UzdyVhPFUOvFY8jG3x_cP81FE
false

對我來說,除了 +-/_= 之外,哈希值都是相同的

有人發現我的錯誤嗎? 與我的 base64 編碼有關。

更新

我又玩了一些,這里的 base64 編碼似乎有些奇怪。 節點js中的以下代碼:

console.log(signature);
var b = new Buffer(signature, 'base64');
console.log(b.toString('base64'));

產量:

pEwNPJ-LUHBdvNx631UzdyVhPFUOvFY8jG3x_cP81FE
pEwNPJLUHBdvNx631UzdyVhPFUOvFY8jG3xcP81F

這看起來很奇怪,對吧?

感謝蒂莫西·米德 (Timothy Meade) 發表評論並將我推向正確的方向。

Node 的 Buffer 類型使用 +、/ 和 = 生成標准 Base64

這里提到了一個 URL 安全 base64 編碼: http : //en.wikipedia.org/wiki/Base64

它將 + 替換為 -,/ 替換為 _ 並且 = 是可選的。 在 QueryString (d'uh) 上傳遞的令牌是 URL 安全版本。 因此差異。

代碼由一個簡單的修復:

out = out.replace('+','-').replace('/','_').replace('=','');

我前段時間寫了這個庫,我猜你可以使用一些代碼。 它應該在 node.js 和現代瀏覽器中運行。

這不是您嘗試使用的確切方法,但我相信這是在 NodeJS 中驗證 JWT 的首選方法。 請注意,我使用 NPM base64url庫在 base64Url(JWT 的默認編碼)和base64 (NodeJS 期望的驗證功能)之間進行轉換。

另請注意,您需要公鑰和私鑰對分別進行簽名和驗證。 我在這篇文章的底部包含了用於簽署和驗證此 JWT 的私鑰和公鑰。

const base64 = require('base64url');
const crypto = require('crypto');
const verifyFunction = crypto.createVerify('RSA-SHA256');
const fs = require('fs');

// The sample JWT from https://jwt.io/
const JWT = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.POstGetfAytaZS82wHcjoTyoqhMyxXiWdR7Nn7A29DNSl0EiXLdwJ6xC6AfgZWF1bOsS_TuYI3OG85AmiExREkrS6tDfTQ2B3WXlrr-wp5AokiRbz3_oB4OxG-W9KcEEbDRcZc0nH3L7LzYptiy1PtAylQGxHTWZXtGz4ht0bAecBgmpdgXMguEIcoqPJ1n3pIWk_dUZegpqx0Lka21H6XxUTxiy8OcaarA8zdnPUnV6AmNP3ecFawIFYdvJB_cm-GvpCSbr8G8y_Mllj8f4x9nBH8pQux89_6gUY618iYv7tuPWBFfEbLxtF2pZS6YC1aSfLQxeNe8djT9YjpvRZA';

// This just gets the value of the public key (same as the one at bottom of this post)
const PUB_KEY = fs.readFileSync(__dirname + '/id_rsa_pub.pem', 'utf8');

// Split the JWT by `.` to get each part
const jwtHeader = JWT.split('.')[0];
const jwtPayload = JWT.split('.')[1];
const jwtSignature = JWT.split('.')[2];

// We only need the first two pieces to verify
verifyFunction.write(jwtHeader + '.' + jwtPayload);
verifyFunction.end();

// IMPORTANT: NodeJS expects base64 format, not base64url format!
const jwtSignatureBase64 = base64.toBase64(jwtSignature);

// IMPORTANT: You need to specify that the `jwtSignatureBase64` data is base64 format, 
// otherwise, it will default to Buffer format and return false
const signatureIsValid = verifyFunction.verify(PUB_KEY, jwtSignatureBase64, 'base64');

console.log(signatureIsValid); // true

下面的鍵來自這里提到的示例 JWT。

私鑰:

-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAnzyis1ZjfNB0bBgKFMSvvkTtwlvBsaJq7S5wA+kzeVOVpVWw
kWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHcaT92whREFpLv9cj5lTeJSibyr/Mr
m/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIytvHWTxZYEcXLgAXFuUuaS3uF9gEi
NQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0e+lf4s4OxQawWD79J9/5d3Ry0vbV
3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWbV6L11BWkpzGXSW4Hv43qa+GSYOD2
QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9MwIDAQABAoIBACiARq2wkltjtcjs
kFvZ7w1JAORHbEufEO1Eu27zOIlqbgyAcAl7q+/1bip4Z/x1IVES84/yTaM8p0go
amMhvgry/mS8vNi1BN2SAZEnb/7xSxbflb70bX9RHLJqKnp5GZe2jexw+wyXlwaM
+bclUCrh9e1ltH7IvUrRrQnFJfh+is1fRon9Co9Li0GwoN0x0byrrngU8Ak3Y6D9
D8GjQA4Elm94ST3izJv8iCOLSDBmzsPsXfcCUZfmTfZ5DbUDMbMxRnSo3nQeoKGC
0Lj9FkWcfmLcpGlSXTO+Ww1L7EGq+PT3NtRae1FZPwjddQ1/4V905kyQFLamAA5Y
lSpE2wkCgYEAy1OPLQcZt4NQnQzPz2SBJqQN2P5u3vXl+zNVKP8w4eBv0vWuJJF+
hkGNnSxXQrTkvDOIUddSKOzHHgSg4nY6K02ecyT0PPm/UZvtRpWrnBjcEVtHEJNp
bU9pLD5iZ0J9sbzPU/LxPmuAP2Bs8JmTn6aFRspFrP7W0s1Nmk2jsm0CgYEAyH0X
+jpoqxj4efZfkUrg5GbSEhf+dZglf0tTOA5bVg8IYwtmNk/pniLG/zI7c+GlTc9B
BwfMr59EzBq/eFMI7+LgXaVUsM/sS4Ry+yeK6SJx/otIMWtDfqxsLD8CPMCRvecC
2Pip4uSgrl0MOebl9XKp57GoaUWRWRHqwV4Y6h8CgYAZhI4mh4qZtnhKjY4TKDjx
QYufXSdLAi9v3FxmvchDwOgn4L+PRVdMwDNms2bsL0m5uPn104EzM6w1vzz1zwKz
5pTpPI0OjgWN13Tq8+PKvm/4Ga2MjgOgPWQkslulO/oMcXbPwWC3hcRdr9tcQtn9
Imf9n2spL/6EDFId+Hp/7QKBgAqlWdiXsWckdE1Fn91/NGHsc8syKvjjk1onDcw0
NvVi5vcba9oGdElJX3e9mxqUKMrw7msJJv1MX8LWyMQC5L6YNYHDfbPF1q5L4i8j
8mRex97UVokJQRRA452V2vCO6S5ETgpnad36de3MUxHgCOX3qL382Qx9/THVmbma
3YfRAoGAUxL/Eu5yvMK8SAt/dJK6FedngcM3JEFNplmtLYVLWhkIlNRGDwkg3I5K
y18Ae9n7dHVueyslrb6weq7dTkYDi3iOYRW8HRkIQh06wEdbxt0shTzAJvvCQfrB
jg/3747WSsf/zBTcHihTRBdAv6OmdhV4/dD5YBfLAkLrd+mX7iE=
-----END RSA PRIVATE KEY-----

公鑰:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnzyis1ZjfNB0bBgKFMSv
vkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHc
aT92whREFpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIy
tvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0
e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWb
V6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9
MwIDAQAB
-----END PUBLIC KEY-----

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM