email360 / ssjs-lib

An open-source library that takes the repetitive and complex tasks and simplifies them, enabling you to get the most out of Salesforce Marketing Cloud.
http://www.email360.io
Other
50 stars 14 forks source link

Issue with JWT sign function #10

Open ghingis opened 1 year ago

ghingis commented 1 year ago

There is an issue with this sign function. You parse the JSON and then stringify it again, while this is unnecessary, it might also alter the payload. Like changing the order of properties or losing serialization information like newlines or whitespaces. Hence the signature will inevitably change and won't match the original.

(The same issue can happen with the header, but sadly you have no control over that.)

https://github.com/email360/ssjs-lib/blob/master/core/lib_jwt.ssjs#L184-L191

shdinx commented 1 year ago

Thank you @ghingis you are absolute right.

Stringify on object may not result in the same output. Properties of non-array objects are not guaranteed to be stringified in any particular order. We can not rely on ordering of properties within the same object within the stringification.

That said, the stringification IS necessary as in SSJS you do not have any JWT methods to use for now. The SSJS Lib is utilising the AMPScript function GetJWTByKeyName and the payload is required as a string.

When signing or creating the JWT it stays on the same system and both methods are using the same stringification. As said above, there is no guarantee that the output of both is the same but I have run thousands of simulated tests with all different types of payload and it has not failed yet. Certainly it will eventually but I have not come across it yet.

I also want to point out the Stringify in SSJS seems not to be the same as the JSON.stringify() version in JS. This may be the case due to the age of the SSJS .NET interpreter (JINT) in Salesforce Marketing Cloud.

I spend weeks on looking into HMAC for SSJS to not only utilise JWT but also TOTP. Unfortunately the SSH256 method in SSJS is also very limited and can not handle anything beside string inputs which will not work with HMAC. You may think you can re-write SSH256, which I also spend time on to find out that SSJS has many issues with bit shifting and XORs.

Bottom line - if you have a safer solution using JWT in SSJS and be able to verify the JWT, please share. For now this is the only thing I could come up with and it works till the moment the non-array object order changes during processing

ghingis commented 1 year ago

Yeah, SFMC is lacking in this area, but still... Stringification is only necessary if you parse it, the payload is already a urlbase64 encoded string. If you would just base64 decode it and omit the parse part, you would not have to stringify it..