Caveats of JSON hashing: how to make sure your services communicate effectively
Caveats of JSON hashing: how to make sure your services communicate effectively

Caveats of JSON hashing: how to make sure your services communicate effectively

Sometimes when doing application development, you are using multiple services, possibly in multiple languages. Let’s say you have a backend and a frontend application, and they communicate through JSON. For security purposes, some fields may need to be hashed, encoded or encrypted on one end. Recovery happens at the other end. But how to avoid surprises?

πŸ—„ ORDERING

Set a key ordering standard. Either alphabetically or in a given predefined order agreed on both ends. The following JSONs are equivalent, but represent a different original message: {"apples": 2, "bananas": 5}, {"bananas": 5, "apples": 2}. Some languages, like Python, have special structures like OrderedDict that ensure a dictionary keeps its ordering in place. Python also optionally uses a (boolean) sort_keys argument when converting dictionaries to strings.

πŸ¦† TYPING

When using a JSON as a string, or original message, consider the typing of all values. {"apples": 2}, {"apples": "2"} and {"apples": 2.0} are all valid JSONs and kind-of mean the same thing, but they are not represented the same as strings.

E.g. {"apples": 2} == {"apples": 2.0} is True! But json.dumps({"apples": 2}) == json.dumps({"apples": 2.0}) is False.

πŸšͺSEPARATORS

Make sure you use the same standard for stringifing JSONs, at both (or all) ends of communication. A good idea is to simply strip spaces, e.g. json.dumps({"apples": 5}, separators=(",", ":")) will result in the most compact form: {"apples":5}

πŸ₯Έ ENCODING

This one is a no-brainer, but make sure you use the same algorithm on encoding and decoding.

>>> original_message = json.dumps({"apples": "2"}, separators=(",", ":"))
>>> original_message
'{"apples":"2"}'
>>> import hashlib
>>> hashlib.sha256(original_message.encode("utf-8")).hexdigest()
'9a00d4d406c5f5e68eeca4375f6221f0a8efc3f77b88f09640a9faa86382164e'
>>> hashlib.sha512(original_message.encode("utf-8")).hexdigest()
'634bb6510b08da98d2f46b1b82e00de669b4c574837445cdc2aeb761b006839c0e6ffdc481f908d9ccde6b19abec4ad1081acf431dcb2a11bc69a1bdb14a1c9f'

Happy coding and the less surprises, the better!