Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jwt token decoding even when wrong token is provided for some letters #337

Closed
flyingboy007 opened this issue Oct 21, 2019 · 2 comments
Closed

Comments

@flyingboy007
Copy link

flyingboy007 commented Oct 21, 2019

I was just trying out jwt tokens on a rails app. Using this jwt library.

JWT.encode({sss: "333"}, 'SECRET_KEY')

 #returned 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 upto 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 a bug or am I doing something wrong here?

@flyingboy007
Copy link
Author

flyingboy007 commented Oct 22, 2019

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.

Credits: Thank you JPS for giving the answer in SO.

@jamb1975
Copy link

Base64.Decoder decoder = Base64.getUrlDecoder();
log.info("Payload Json-> {}", decoder.decode(token.split("\.")[0]) );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants