JWT token decoding even when the last character of the signature is changed

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 (24 bits), the base64 encoded result is 4 characters long, each character representing a 6 bit value, so 4 * 6 bits = 24 bits. If the number of bits that need to be encoded can’t be divided by 6 without remainder, there’ll be one character more with 2 or 4 insignificant 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 bytes) 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.

The following table illustrates that. It shows the last 4 base64 characters of the signature, including the possible changes of the last character (A-D) and the bit and byte number of the original data:
enter image description here
The change of the last character in that range only causes a change of the last two bits (light grey) but does not change the original data, because the changed bits are beyond the last bit of the original data.

If you’re really concerned about the 2 bits on the end, you can consider to change the signature algorithm to HS384.

Then you have a 384 bit (= 48 byte) hash, which is represented in 64 Base64 characters. 384 can be divided by 8 and by 6 without remainder, so there are no insignificant bits on the end and any change on the last character will lead to a failed verification.

HS512 would have the same “problem” as HS256, and then even 4 insignificant bits on the end, but nonetheless a longer hash (512 bits vs. 384 bits vs. 256 bits) is considered more secure.

Conclusion: it’s all fine, nothing wrong here. The verification of a signature is based on its binary value, which is not affected by the peculiarities of the encoding. You can change the algorithm, if you’re worried, but I think it’s not really necessary and the choice of an algorithm should not be based on that.

Leave a Comment