使用OpenSSL验证JWT(RS256)



我的要求是使用公钥(RS256(验证JWT。检查应仅基于本机OpenSSL。

我使用JWT.IO的初始内容进行测试。此令牌已生成:

eyJhbGciOiJSUz11NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIwibmFtZSI6IkpvaG4gRG9lIiwiRtaW4iOnRydWUsImlhdCI6MTUxNjIzotayMn0.POstGetfAytaZS82wHcJoTyoqhMyxXiWdR7N7A29DNSl0EiXLdwJ6xC6AfgZWF1bOsS_TuYI3OOG85AmiExREkrS6tDfTQ2B3Wlrr-wp5AokiRbz 3_oB4OxG-W9KcEEbDRcZc0nH3L7LzYptiy1PtAylQGxHTWZXtGz4ht0bAcbBgmpdgXMguEIcoqPJ1n3pIWk_dUZegpqx0Lka21H6XxUTxiy8OcaarA8zdnUnV6AmNP3ecFawIFYdvJB_cm-GvpCSbr8G8y_Mllj8f4x9nBH8pQux89_6gUY618iYv7tuPWBFfEbLxtF2pZS6YC1aSfLQxeNe8djT9YjpvRZA

当我输入Header+Payload+Signature(下图中的项目1和2(时,它们之间有点。接下来,我输入一个公钥(图片中的项目3(。因此,我看到消息"签名已验证"(图片中的项目4(。

现在我想使用OpenSSL获得相同的结果

我已经执行了以下步骤:

  1. 创建文本文件/tmp/pub.pem并将以下内容复制到其中(从JWT.IO测试用例复制(:

-----开始公钥----MIIBIjANBgkqhkiG9w0BAQEFAOCAQ8AMIBCgKCAQEAnzyis1ZjfNB0bBgKFMSvvkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHcaT92hhRefpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11英寸tvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWbV6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9MwIDAQAB-----结束公钥-----

  1. 创建文本文件data/tmp/data.txt并将下面的内容放入其中。这是由点分隔的Header和Payload(图片中的项目1(:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwimFtZSI6IkpvaG4gRG9lIiwiYWrtaW4OnRydWUsImlhdCI6MTUxNjIzotayMn0

  1. 创建文本文件data/tmp/signature.txt并将以下内容放入其中(这是图片中的第2项(:

POstGetfAytaZS82wHcjoTyoqhMyxXiWdR7Nn7A29DNSl0EiXLdwJ6xC6AfgZWF1bOsS_TuYI3OG85AmiExREkrS6tDfTQ2B3Wxrr-wp5AokiRbz3_oB4OxG-W9KcEEbDRc0nH3L7LzYptiy1PtAylQGgHTWZXtGz4ht0bAcBgmpdgXMguEIcoqPJ1n3pIWk_dUZegpqx0Lka21H6XxUTxiy8OcaarA8zd nPunV6AmNP3ecFawIFYdvJB_cm-GvpCSbr8G8y_Mllj8f4x9nBH8pQux89_6gUY618iYv7tuPWBFfEbLxtF2pZS6YC1aSfLQxeNe8djT9YjpvRZA

  1. 我运行OpenSSL命令:

    openssl dgst -verify /tmp/pub.pem -keyform PEM -sha256 -signature /tmp/signature.txt -binary /tmp/data.txt
    

    但得到的结果:

    验证失败。

我到底做错了什么?

JWT的签名是base64url编码的,需要首先解码。建议的重复只处理base64编码的签名,而openssl似乎不处理base64url编码。

如果你在Windows系统上工作,你可以用certutil解码签名文件,它可以直接解码bas64url:

certutil -decode signature.txt signature.sha256

然后使用signaturesha256作为openssl:的输入

openssl.exe dgst -sha256 -verify pubkey.pem -signature signature.sha256 data.txt

然后你应该得到结果:

验证正常

我发现这个要点在从开始JWT到将其分解、解码某些比特,然后根据签名验证有效载荷方面非常有用。它使用openssl和perl,这应该与大多数Bash实现一起提供。

我会粘贴相同内容的"短"版本。在我的情况下,我正在验证来自Auth0的JWT。

# The JWT itself
jwt=eyJ...
# Get Auth0's public certificate
curl https://your_auth0_domain/pem > auth0publiccert.pem
# Extract the public key from the public certificate
openssl x509 -pubkey -noout -in auth0publiccert.pem > auth0publickey.pem
# Extract the input payload
input=${jwt%.*}
echo -n $input > payload.txt
# Extract the signature portion
encSig=${jwt##*.}
# Decode the signature
echo -n $encSig | perl -ne 'tr|-_|+/|; print "$1n" while length>76 and s/(.{0,76})//; $_ .= ("", "", "==", "=")[length($_) % 4]; print' | openssl enc -base64 -d > signature.dat
# Finally, verify
openssl dgst -sha256 -verify auth0publickey.pem -signature signature.dat payload.txt
#Output should be "Verified OK"

最新更新