1

the problem is: I have a request with params like:

{ "foo": "bar", "bar": "baz", "baz" : { "nestedKey": "foo" } }

I need to sign it with Hmac512 algorithm, so I'll need to stringify the object first.

But, my concern is, if the order of the key isn't preserved, the signature generated by server and the client could be different.

to handle that, my idea is simply to order the keys of the object (including the keys nested inside that object).

how can I achieve this?

pedrofb
  • 37,271
  • 5
  • 94
  • 142
Ramadoka
  • 352
  • 3
  • 25
  • Possible duplicate of [Does JavaScript Guarantee Object Property Order?](https://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order) – besciualex Jul 12 '18 at 12:46
  • 1
    One option is - You can use object.keys to get the keys and then sort the keys and recreate the object. – Nikhil Mittal Jul 12 '18 at 12:47
  • 1
    If I were you, I'd probably do as @NikhilMittal said. If you have nested objects, you'll have to do that recursively until you get to the bottom... Quite a PITA. Interesting question anyway ;) – sjahan Jul 12 '18 at 12:49
  • 1
    Why does the order matter for signing? Don't you send the signed text along, but create it at the other end independently? – Bergi Jul 12 '18 at 12:55
  • I'm not sure if I can get the original string instead of the parsed Object in expressjs with bodyParser.json() middlewares. – Ramadoka Jul 12 '18 at 13:47
  • @Ramadoka You definitely should do that rather than re-stringifying it. Maybe you'll want to ask a new question on how to work around the express default bodyParser – Bergi Jul 12 '18 at 14:36
  • You can't "recreate" the object in a deterministic way. Javascript object's layout in memory, the order of the elements, etc, is NOT deterministic by definition of a Javascript object. Only an array works if you want order. – Larry K Jul 13 '18 at 14:30

2 Answers2

2

As stated in the OP, the input to the HMAC process must be deterministic.

But Javascript object elements' order cannot be set, no matter how much we'd like them to be settable. (I see this question re-occur every so often.)

Answer is to sort the the stringified string itself.

See json-stable-stringify for a solution.

Then feed the resulting string into the HMAC method. No need to base64 encode it.

Larry K
  • 47,808
  • 15
  • 87
  • 140
0

You need to ensure that the message is the same in both sides, but you should not need to modify or adapt the message at all

Basically apply this algorithm

 base64(sign(utf8(json message)))

Client side

  1. Stringify: Convert the javascript object to string

  2. UTF-8: Ensure you are using a known and fixed encoding like utf

  3. Sign: Calculate HMAC over the resulting message

  4. base64: Convert the binary signature to base64

Send to client the json message and the signature

Server side

Get the raw message from client and apply steps 2-4. Check if the signatures are equal

pedrofb
  • 37,271
  • 5
  • 94
  • 142
  • 1
    What's the `base64` step 3 good for? Wouldn't you rather do that on the binary result of the HMAC? – Bergi Jul 12 '18 at 12:57
  • Opps, Somehow I mixed the steps. Thanks @Bergi – pedrofb Jul 12 '18 at 13:05
  • 1
    -1 because the stringify operation is not deterministic. Javascript object elements' order cannot be set, no matter how much we'd like them to be. See my answer for alternative to stringify – Larry K Jul 13 '18 at 14:22
  • @LarryK The order of the elements of stringify is irrelevant if you apply HMAC on the server over the raw data sent by the client. It is much simpler and less prone to errors than recreating the javascript object and reapplying the entire signature algorithm. Maybe my answer does not respond exactly to what the OP asks like yours, but it is simpler and fulfills the same final goal (if I have understood correctly, it is to validate integrity and authenticity of a request). In any case thanks for the comment! – pedrofb Jul 13 '18 at 15:10