问题
I was just trying out JWT tokens on a rails app, using this jwt library: https://github.com/jwt/ruby-jwt
JWT.encode({sss: "333"}, 'SECRET_KEY')
returns below token:
eyJhbGciOiJIUzI1NiJ9.eyJzc3MiOiIzMzMifQ.CwX_1FztYHVpyx_G27u938SceilsVc5AB5Akwqlo2HA
Then I decoded using the above token
JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJzc3MiOiIzMzMifQ.CwX_1FztYHVpyx_G27u938SceilsVc5AB5Akwqlo2HA", 'SECRET_KEY')
returns below response correctly:
[{"sss"=>"333"}, {"alg"=>"HS256"}]
But if I try to change the last letter of the token to B instead of current A it is still returning the same response which is weird.
JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJzc3MiOiIzMzMifQ.CwX_1FztYHVpyx_G27u938SceilsVc5AB5Akwqlo2HB", 'SECRET_KEY')
Getting this response even though the token I provided is wrong:
[{"sss"=>"333"}, {"alg"=>"HS256"}]
Actually I am getting the same response for all characters up to 'D'
If I use F and others above then its showing error as expected:
JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJzc3MiOiIzMzMifQ.CwX_1FztYHVpyx_G27u938SceilsVc5AB5Akwqlo2HF", 'SECRET_KEY')
JWT::VerificationError (Signature verification raised) from (irb):34
What could be the reason for this? Is it the expected behavior or am I doing something wrong here?
回答1:
The reason is the base64url encoding. The three parts of a JWT are all base64url encoded. Base64 encoding transforms the input data to a 6-Bit representation, mapped to a set of 64 ASCII characters. If you have 3 bytes source data, the base64 encoded result is 4 characters long, each character representing a 6 bit value, so 4 * 6 bits = 24 bits.
In your case, the encoded signature has 43 characters, which means 43 * 6 = 258 bits. So you could theoretically encode 258 bits, but the signature is only 256 bits (32 byte) long, which means there are 2 insignificant bits on the end.
A look on the base64 encoding table shows that 'A' to 'D' represent the 6 bit values 0 (000000) to 4 (000011), so the first four bits, which are still significant, are all identical, and only the last two, insignificant bits are changing. But the character 'E' stands for 5 (000100) and would change the last bit of the 256 bit value.
Conclusion: it's all fine, nothing wrong here, it works as expected.
来源:https://stackoverflow.com/questions/58492009/jwt-token-decoding-even-when-the-last-character-of-the-signature-is-changed