Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Javascript's JSON.stringfy the same as PHP's json_encode?

I'm trying to do an HMAC SHA256 hash of stringified data using both JavaScript (CryptoJS Libraries) and PHP (built in HMAC function). I'm concerned that the JavaScript JSON.stringify will not be consistent/identical to the PHP json_encode() function. Is there a better approach to this stringifying of the data (object/array)?

Here's my test, which works. But, I'm concerned about Spanish characters and other encodings/entities that the code may encounter.

<h1>Testing HMAC Javascript to PHP Comparison</h1>

<br><br>

<div id="php_mac">
<?php
// Testing HMAC
$security_key = '0123456789';
$obj = array(
    'field1' => 1,
    'field2' => '2',
    'field3' => "'",
);

// Calculate HMAC SHA256
$str_data = json_encode($obj);
echo "PHP str_data: ".$str_data."<br>";
$hash = hash_hmac('sha256', $str_data, $security_key, true);
$hashInBase64 = base64_encode($hash);
echo "PHP hashInBase64: ".$hashInBase64;
?>
</div>

<br><br>

<div id="javascipt_hmac">

    <div id="javascript_str_data"></div>
    <div id="javascript_hashInBase64"></div>

<script>

var security_key = '0123456789';
var obj = {
    'field1': 1,
    'field2': '2',
    'field3': "'",
};

// Create security hash based on posted data
var str_data = JSON.stringify(obj);
$('#javascript_str_data').html('str_data: '+str_data);
// Using CryptoJS to HMAC SHA256 the str_data
var hash = CryptoJS.HmacSHA256(str_data, security_key);
var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
$('#javascript_hashInBase64').html('JS hashInBase64: '+hashInBase64)

</script>

</div>

Additional thoughts: I'm worried about spacing/quoting differences with JSON methods. Perhaps I should loop thru the object/array and use the "values" only to produce the string of data to be HMAC'ed? Assuming this can be kept to a single array/object, that should produce a consistent "values" string. But, then how do you keep a consistent ordering. I assume it could be ordered by key first.

like image 638
jjwdesign Avatar asked Oct 31 '22 10:10

jjwdesign


1 Answers

As @Pointy mentioned in the comments, the output of JSON.stringify and json_encode may have slight differences in two scenarios:

  1. An object's key/value ordering (objects are unordered)
  2. "Simple" values

On "simple" values, the PHP documentation has this to say:

Like the reference JSON encoder, json_encode() will generate JSON that is a simple value (that is, neither an object nor an array) if given a string, integer, float or boolean as an input value. While most decoders will accept these values as valid JSON, some may not, as the specification is ambiguous on this point.
To summarise, always test that your JSON decoder can handle the output you generate from json_encode().

If you're worried about the data being 100% faithfully recreated, consider encoding the data before storing it (i.e. base64_encode it).

P.S. If you're going to HMAC the data, you need to 1) only HMAC the values and 2) make sure you always access the values in the same order every time because JSON makes no ordering promises for anything except arrays.

like image 148
Mr. Llama Avatar answered Nov 10 '22 17:11

Mr. Llama