无法使用base64 -d正确解码jwt负载

问题描述 投票:0回答:1

JWT 由三个部分组成,用点分隔: header.payload.signature

我有以下有效负载,我正在尝试使用

base64 -d
命令在终端中对其进行解码:

  payload=eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY3OTMxMzgyMSwiaWF0IjoxNjc5MTQxMDIxLCJqdGkiOiIzZjM4ZTVmZTBmNGE0N2E0ODg2MGM4M2FmYmNhNTAzZiIsInVzZXJfaWQiOjEwfQ

当尝试使用

echo $payload | base64 -d
解码有效负载时,我得到以下输出:

{"token_type":"refresh","exp":1679313821,"iat":1679141021,"jti":"3f38e5fe0f4a47a48860c83afbca503%

输出不包含整个json,它被截断了。

在 Chrome javascript 控制台中使用

atob(payload)
时,这是输出:

{"token_type":"refresh","exp":1679313821,"iat":1679141021,"jti":"3f38e5fe0f4a47a48860c83afbca503f","user_id":10}

这是我期望从解码有效负载中得到的正确的 json 输出

我有以下问题:

  1. 据我所知,这两个函数都只是对其输入进行 Base64 解码,为什么这些输出会有所不同?
  2. 如何使用
    base64 -d
    或类似命令解码终端中的有效负载?

提前致谢!

附加信息

  1. which base64
    返回
    /usr/bin/base64
  2. 我使用的是 OS X
shell jwt base64
1个回答
0
投票

您的

$payload
值具有 Base64 编码,但缺少最终填充。来自维基百科:Base64

由于 Base64 是六位编码,并且解码后的值被分为 8 位八位字节,因此 Base64 编码文本的每四个字符(4 个六位字节 = 4 × 6 = 24 位)代表三个八位字节的未编码文本或数据(3 个八位字节 = 3 × 8 = 24 位)。这意味着,当未编码输入的长度不是三的倍数时,编码输出必须添加填充,使其长度为四的倍数。填充字符是

=
,这表示不需要更多位来完全编码输入。 […]

填充字符对于解码来说不是必需的,因为可以从编码文本的长度推断出丢失的字节数。在某些实现中,填充字符是强制性的,而对于其他实现则不使用。

事实证明,JWT 令牌不愿意生成填充字符,而您的

base64
解码器则需要它们的存在。所讨论的实际令牌有 150 个字符,还差两个字符,无法被 4 整除。因此,附加这两个缺失的字符将解决此特定标记的问题,而从变量值的长度推断附加字符的数量将解决一般情况的问题:

echo "$payload==" | base64 -d
# or
echo "$payload$(printf %$(((4-${#payload}%4)%4))s | tr ' ' =)" | base64 -d
{"token_type":"refresh","exp":1679313821,"iat":1679141021,"jti":"3f38e5fe0f4a47a48860c83afbca503f","user_id":10}

或者,使用可以处理不平衡填充的解码器,例如命令行 JSON 处理器jq(您也可以使用它来直接对解码后的令牌进行后处理):

echo "$payload" | jq -R '@base64d | fromjson'
# or
jq -n --arg p "$payload" '$p | @base64d | fromjson'
{
  "token_type": "refresh",
  "exp": 1679313821,
  "iat": 1679141021,
  "jti": "3f38e5fe0f4a47a48860c83afbca503f",
  "user_id": 10
}
© www.soinside.com 2019 - 2024. All rights reserved.