Why is a JWT signature not unique for a specific payload - base64

My application is using JWT and should prevent replay attacks. I was testing this an ran into the following.
When I have a valid JWT and change the last character of the token/signature the JWT is still valid. E.g. the following token do all validate correctly:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTb21lIFRlc3QiLCJjbGFpbSI6IlNvbWUgQ2xhaW0ifQ.UkFYSK7hSSeiqUOSMdbXgbOErMFnuK0Emk1722ny-r4
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTb21lIFRlc3QiLCJjbGFpbSI6IlNvbWUgQ2xhaW0ifQ.UkFYSK7hSSeiqUOSMdbXgbOErMFnuK0Emk1722ny-r5
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTb21lIFRlc3QiLCJjbGFpbSI6IlNvbWUgQ2xhaW0ifQ.UkFYSK7hSSeiqUOSMdbXgbOErMFnuK0Emk1722ny-r6
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTb21lIFRlc3QiLCJjbGFpbSI6IlNvbWUgQ2xhaW0ifQ.UkFYSK7hSSeiqUOSMdbXgbOErMFnuK0Emk1722ny-r7
I have checked this on http://jwt.io/ and can be reproduced in my .Net application as well.
Can someone explain how it is possible that the signature is not unique for a given payload? I understand that collisions can occur, but I cannot explain that they are consecutive sequences.

In this special case you are changing the base64 url encoding of the signature, not the signature itself
The fourth base64 values encode the same binary value. Try converting to hexadecimal at http://kjur.github.io/jsjws/tool_b64udec.html
The value you will see is
52415848aee14927a2a9439231d6d781b384acc167b8ad049a4d7bdb69f2fabe
If you change the suffix to -r1 or -r8 then the binary value changes and signature validation will fail
Can two different BASE 64 encoded strings result into same string if decoded?

When you change the signature (the last part) you can still decode the JWT to see the header and payload. However, if you attempt to validate the JWT with the changed signature, that validation will fail.

Related

Base64 for auth

I need to build a XMPP client. The server PLAIN mechanism to auth. (using zlib compression I think)
I captured trafic from other xmpp system thats use PLAIN mechanism and the text appear to be Base64 (id + token) ADc1Y2M2OWY0MzQwMTUwMjgyOWIwMWY2MDAyN2E0NDE2ADE1YTk0NzM3NTRiYjY2MGExMGYzYTA5MzA5NWQxMmY3 is what the client return. I put that into a Base64 decoder and its give me this : 75cc69f43401502829b01f60027a441615a9473754bb660a10f3a093095d12f7.
When I encode this using a Base64 encoder, Its give me something else than the first Base64 string (NzVjYzY5ZjQzNDAxNTAyODI5YjAxZjYwMDI3YTQ0MTYxNWE5NDczNzU0YmI2NjBhMTBmM2EwOTMwOTVkMTJmNw)
Can someone explain me? I couldn't find anything on google.
Edit:
https://xmpp.org/extensions/xep-0034.html#example-3
the result of your decoding is not correct, in fact the decoded value
contains two binary values that can't be displayed as a character
(here substituted by a �):
�75cc69f43401502829b01f60027a4416�15a9473754bb660a10f3a093095d12f7.
What you encoded then is based on a string in which the two binary
values are not present, so you encoded basically something different
and got of course a different result.
From jps

DocuSign - Signature part from JWT configuration

Following this tutorial I'm stuck with figuring out what the part of the signature is supposed to keep.
What is the final struct from the JWT to request access token?
What I'm using is this string:
Base64UrlEncoded(header).Base64UrlEncoded(body).RSASHA256(Base64UrlEncoded(header).Base64UrlEncoded(body), provided_private_rsa_key)
Is this the supposed way of doing it? What I've noticed is that the tutorial in the signature part shows an example completely different from what they describe.
Thank you in advance!
Per JWT.IO, it looks like the format of the signature should be RSASHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret). If the periods in your code don't correspond to literal .s, then those would need to be added.
I'd recommend taking the assertion you're generating and plugging it in to JWT.IO's Debugger along with your public key to confirm you've generated a valid assertion.

Amazon MWS - Don't understand how to generate HMAC

In the moment I'm struggling a little bit with the generation of HMAC for Amazon MWS.
I thought I understood how it works.
With the Scratchpad I generated a request. Scratchpad shows the string to sign and also the SHA 256 HMAC and the Base64 HMAC.
The string to sign consists of 4 lines like it's described in the docu.
There are several Onlineconverter for HMAC. I tried:
https://www.freeformatter.com/hmac-generator.html
https://codebeautify.org/hmac-generator
When I convert the string to sign which Scratchpad generated (the 4 lines), I get an other SHA 256 HMAC then Scratchpad generated.
Also there are several Onlineconverter for Base64. I tried:
https://www.freeformatter.com/base64-encoder.html
https://www.base64encode.org
When I convert the SHA 256 HMAC which Scratchpad generated, I get an other Base64-String then Scrathpad generated.
This confuses me. What I don't understand?
Other point:
Later I think I want to use GET and not POST. Do I get this right, that the string to sign for GET also has to be in 4 lines and not in one line as it would be executed later? That's how I understand the docu.
I used these links:
http://docs.developer.amazonservices.com/en_US/dev_guide/DG_QueryString.html
http://docs.developer.amazonservices.com/en_US/dev_guide/DG_SigningQueryRequest.html
https://mws.amazonservices.com/scratchpad/index.html
To answer my own questions.
Generate SHA256 with an Onlineconverter:
I suppose the Problem is the LF. The Onlineconverter maybe have problem with it. Maybe they use CRLF. Better don't try to check your SHA256 with Onlineconverters.
Generate base64 with an Onlineconverter:
The SHA256 Scratchpad shows is not the value you convert with base64. You have to convert the Hex-Value of the SHA256.
Query to sign with GET:
If you want to use GET, the query to sign has to look like the query to sign for POST. Also the four lines. Only swap POST with GET.

Why does cookie-signature in nodejs/express compare signatures using sha1-hashing?

I was just looking into the implementation of the cryptograhic signing extension for express which allows creation of signed cookies.
The mac in the signing function is calculated as described here:
create an instance of SHA256
hash the data value
create a base64 encoded digest
remove trailing equal characters ('=')
The result is a concatenation of the original value and the calculated mac.
On verification of the signature the value is signed again. But then not the signatures are tested on equality, but the overall strings consisting of the original value and the appended mac are compared:
return sha1(mac) == sha1(val) ? str : false;
Here "mac" contains the original value concatenated with a freshly calculated mac, "val" contains the input string as passed to the verification method (consisting of the original value concatenated with a former mac) and "str" is the signed value itself.
See: https://github.com/tj/node-cookie-signature/blob/master/index.js
I would have expected that only the macs would be compared. But this is not the case. Why have the authors chosen this way of implementing the verification? What is the reason for this? And especially: Why don't they compare char by char but a hash of sha1?
The implementation's sign function returns the value concatenated with '.' and HMAC of the value converted to Base64 without the trailing '=' (if any).
The implementation's unsign function does the same with the value part of the given input (up to the '.') and checks if the whole input equals the output of the sign function.
And as to comparing using hash values I the authors were trying to fend off timing attack, whereby an attacker would observe the time it took to check for equality character by character and determine by minute changes between two tries at what character the check failed, and thereafter try to guess on character by character basis the MAC value for the arbitary value part. By comparing using sha1 digest code takes constant time depending only on the given whole input length.
More interesting side note is the removal of padding '=' from Base64 encoded MACs, I have no idea why would they do that as there is URL safe variant of Base64.

double base64 encoding danger & base64 security

I'm adding some capabilities to an api to allow third parties to store user data. I know some users may already base64 encode their user ids before submitting them through the api, others might not.
I've done some checking on double encoding (encoding base64 of an already base64 encoded string), and it doesn't SEEM to be causing any problems.
From my understanding, it isn't possible to check if a string is base64 encoded.
Is there something here I should be looking out for down the line? is there another way I should be doing this, or is it safe?
Also, i'm cleaning the data like this.
$eid=preg_replace("/[^a-zA-Z0-9\/=+]/", "",base64_encode(#$_GET['eid']));
that should be safe to store in the database as it strips out any suspect characters after the string is encoded. But I'll need to return the non-encoded string to through the API.
So at some point I'll need to do echo base64_decode($eid); And it seems to me that this could be an opportunity for a hacker to run malicious code through my server.
Is that right?

Resources