Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Json: PHP to JavaScript safe or not?

Tags:

json

security

php

I understand that the use of eval(json_str) on the client is vulnerable to malicious code. My question is, if json_str was an array constructed by the PHP function json_encode, would I be safe?

For example,

json_str = json_encode(array(record1, 
                             record2, 
                             record3));

would it now be entirely safe to use eval(json_str) inside client-side code?

like image 632
whamsicore Avatar asked Jul 25 '11 13:07

whamsicore


2 Answers

If you want to use Content Security Policy (CSP), you are prevented from executing inline script tags. This would therefore would make bobince's otherwise amazing answer impossible since CSP requires that all JavaScript be in separate files.

How to get your JavaScript in a separate file:

One way around this is to html encode the JSON with PHP (which should prevent XSS) and then echo it to a hidden element and then use JavaScript to get the contents of that tag (adapted from OWASP):

Put this inline (note, it won't actually be executed):

<script id="jsonString" type="application/json">
<?php
// OWASP uses a <script> tag with an invalid "type" attribute, but 
// you can just as easily use a <span style="display:none"> or other
// hidden tag.
//
// Note, this probably won't actually be valid JSON because we are using 
// htmlspecialcharacters() on the JSON data. That doesn't matter because
// this is never actually executed by the browser due to the incorrect
// script type. We will decode it later into valid JSON.
echo htmlspecialchars(json_encode($object), ENT_NOQUOTES); 
?>
</script>

Then in your JavaScript file:

var dataElement = document.getElementById('jsonString');
// Get innerText, which also has the side effect of html decoding
// the string returned, which is just what we want
var jsonString = dataElement.textContent || dataElement.innerText;
// Now you can parse the JSON string
var jsonObj = JSON.parse(jsonString);
like image 180
Mike Avatar answered Oct 03 '22 05:10

Mike


In terms of pure JavaScript, yes, you are safe: the output of json_encode can never containing anything but static values which will have no unexpected side effected when passed to eval. (Though you typically have to surround your JSON string with () when using eval, to avoid it misinterpreting an object literal expression as a statement block.)

Aside: this is not necessarily true of all JSON encoders because there are some characters that are valid to include raw in a JSON string that are not valid raw in JavaScript. Most notably, U+2028 and U+2029 which can't go unescaped in JavaScript string literals as they constitute newlines. However PHP's encoder encodes all non-ASCII characters (eg as "\u2028") so no issue here.

In terms of JavaScript embedded in another language (typically: HTML) you are not necessarily safe. For example:

<script type="text/javascript">
    var v= <?php echo json_encode($value); ?>;
</script>

In this example, what if value contains a string with the character sequence </script? This would allow the value to end the script block prematurely and thus escape into HTML markup, where it could then inject other malicious script.

To avoid this problem, when including JSON content in HTML, always encode the < character in string literals, as \x3C or, in JSON-compliant terms, \u003C. For compatibility with XHTML non-CDATA script blocks, do & as well. For compatibility with JS inside event handler attributes, do quotes as well.

PHP will do this for you with the right options to json_encode():

var v= <?php echo json_encode($value, JSON_HEX_QUOT|JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS); ?>;

(You may want to define a shortcut function to make this quicker to write.)

like image 31
bobince Avatar answered Oct 03 '22 05:10

bobince