I noticed that many people are passing objects from PHP to Javascript as JSON like this:
var obj=JSON.parse('<?php echo json_encode($obj) ?>');
or
var obj=jQuery.parseJSON('<?php echo json_encode($obj) ?>');
Why don't people pass JSON directly like this?
var obj=<?php echo json_encode($obj) ?>;
This works fine with the few objects that I tried. Are there cases when this won't work?
passing objects from PHP to Javascript as JSON like this:
var obj=JSON.parse('<?php echo json_encode($obj) ?>');
Ouch! You're right, this is overcomplicated. Also, it actually has serious problems with apostrophes and backslashes in the JSON string, which are not escaped and destroy the string literal.
Why don't people pass JSON directly?
People who do it properly do it this way indeed.
Are there cases when this won't work?
Yes. There are unicode characters that are valid in pure JSON, but a syntax error in JavaScript - see http://timelessrepo.com/json-isnt-a-javascript-subset for details. However, json_encode would output these as escape sequences anyway.
Generally, you'd use JSON parsers to secure situations where the code returned may be erroneous (instead of crashing your script, it will simply throw an exception and keep going). This is generally a good idea when the JSON is sent from a source you don't have control over. It seems unnecessary when you're in control of both ends (PHP server and JS client).
That said, a "safer" method just for server side would be:
<?php $json_encoded = json_encode ($obj); ?>
var obj=<?php echo ($json_encoded ? $json_encoded : 'null'); ?>;
This makes sure only a valid object is passed into JavaScript.
More info: https://api.jquery.com/jQuery.parseJSON/
Related
I've been searching around for security concerns about using PHP json_encode inside javascript context but I'm not exactly satisfied with the results
I got a lot of warnings about doing this but they always assume that I was going to inject data from the json_encode object directly to HTML without any type of sanitizing at all
So, I want to know if this and only this little snippet presents any security issues (like xss attacks etc)
<?php
$obj = isset($_POST['js']) ? json_encode($_POST['js']) : false;
if ($obj === false) $obj = '{}';
?>
<script>var x = <?php echo $obj ?>;</script>
EDIT:
Changed the snippet to handle json_encode returning false
With that line of code
var x = <?php echo $obj ?>;
...the server application echoes back the data that was submitted to it via the "js" key. It will be client that sent it that will receive it, so if in some way it is malicious, it will be that same client dealing with the consequences.
The actual sending to the server is in fact the irrelevant part of the chain: if one has the data to submit, one can also assign it to the variable x directly without the server's interference (e.g. through browser's dev tools).
It would be a different story if in PHP you would use the data to manipulate a server database, call a service, or otherwise change the application's state, and you would not first validate that data.
As to the use of json_encode: if indeed you verify that the argument is valid JSON (by checking that the return value is not false), it will produce a valid JavaScript object literal. The known cases of incompatibility (characters U+2028 and U+2029) will not occur, as by default json_encode escapes these characters.
It is correct as per coding. However you have to validate the variable x should not be empty or the posted value.
<script>var x = "<?php if(isset($_POST['js']))
{
echo json_encode($_POST["js"]);
}";
</script>
Sometimes json_encode returns false, if return it that js expression will broke. this will works safer.
<script>var x = JSON.parse(<?php echo (json_encode($_POST["js"]) ? json_encode($_POST["js"]) : '{}'));</script>
if json_encode returns false, var x will get just empty object.
I'm fetching JSON code stored in MySQL and it has extra slashes, which I have to remove in order to parse it in JavaScript, after I print it on the page. Right now I'm doing the following:
$save = str_replace("\n", "<br>", $save); // Replace new line characters with <br>
$save = str_replace('\\"', '"', $save); // top-level JSON
$save = str_replace('\\\\"', '\"', $save); // HTML inside top level JSON
$save = str_replace('\\\\\\\\\\"', '\\\\\"', $save); // HTML inside second level JSON
Here is an example JSON code, as it comes out from MySQL:
{\"id\":2335,\"editor\":{\"selected_shape\":\"spot-7488\"},\"general\":{\"name\":\"HTML Test\",\"shortcode\":\"html-test\",\"width\":1280,\"height\":776},\"spots\":[{\"id\":\"spot-7488\",\"x\":9.9,\"y\":22.6,\"default_style\":{\"use_icon\":1},\"tooltip_content\":{\"content_type\":\"content-builder\",\"plain_text\":\"<p class=\\\"test\\\">Test</p>\",\"squares_json\":\"{\\\"containers\\\":[{\\\"id\\\":\\\"sq-container-293021\\\",\\\"settings\\\":{\\\"elements\\\":[{\\\"settings\\\":{\\\"name\\\":\\\"Paragraph\\\",\\\"iconClass\\\":\\\"fa fa-paragraph\\\"},\\\"options\\\":{\\\"text\\\":{\\\"text\\\":\\\"<p class=\\\\\\\"test\\\\\\\">Test</p>\\\"}}}]}}]}\"}}]}
And here is how it's supposed to look in order to get parsed correctly (using jsonlint.com to test):
{"id":2335,"editor":{"selected_shape":"spot-7488"},"general":{"name":"HTML Test","shortcode":"html-test","width":1280,"height":776},"spots":[{"id":"spot-7488","x":9.9,"y":22.6,"default_style":{"use_icon":1},"tooltip_content":{"content_type":"content-builder","plain_text":"<p class=\"test\">Test</p>","squares_json":"{\"containers\":[{\"id\":\"sq-container-293021\",\"settings\":{\"elements\":[{\"settings\":{\"name\":\"Paragraph\",\"iconClass\":\"fa fa-paragraph\"},\"options\":{\"text\":{\"text\":\"<p class=\\\"test\\\">Test</p>\"}}}]}}]}"}}]}
Please note that I have HTML code inside JSON, which is inside another JSON and this is where it gets a bit messy.
My question - is there a function or library for PHP (for JS will work too) which covers all those corner cases, because I'm sure someone will find a way to break the script.
Thanks!
The short answer, which is woefully inadequate, is for you to use stripslashes. The reason this answer is not adequate is that your JSON string might have been escaped or had addslashes called on it multiple times and you would have to call stripslashes precisely once for each time this had happened.
The proper solution is to find out where the slashes are being added and either a) avoid adding the slashes or b) understand why the slashes are there and respond accordingly. I strongly believe that the process that creates that broken JSON is where the problem lies.
Slashes are typically added in PHP in a few cases:
magic_quotes are turned on. This is an old PHP feature which has been removed. The basic idea is that PHP used to auto-escape quotes in incoming requests to let you just cram incoming strings into a db. Guess what? NOT SAFE.
add_slashes has been called. Why call this? Some folks use it as an incorrect means of escaping data before sticking stuff in a db. Others use it to keep HTML from breaking when echoing variables out (htmlspecialchars should probably be used instead). It can also come in handy in a variety of other meta situations when you are defining code in a string.
When escaping data input. The most common escaping function is mysqli_real_escape_string. It's very important to escape values before inserting them in a db to prevent sql injection and other exploits but you should never escape things twice.
So there's a possibility that your code is double-escaping things or that addslashes is getting called or something like magic_quotes is causing the problem, but I suspect it is another problem: some JS code might be supplying this JSON not as a proper JSON string, but one that has been escaped so to define a string within javascript.
If you take your example JSON string above, and slap some quotes around it:
var myJSON = "<put your string here>";
then SURPRISE your javascript is not broken and the var myJSON contains a string that is actually valid JSON and can be parsed into an a valid JSON object:
var myJSON = "{\"id\":2335,\"editor\":{\"selected_shape\":\"spot-7488\"},\"general\":{\"name\":\"HTML Test\",\"shortcode\":\"html-test\",\"width\":1280,\"height\":776},\"spots\":[{\"id\":\"spot-7488\",\"x\":9.9,\"y\":22.6,\"default_style\":{\"use_icon\":1},\"tooltip_content\":{\"content_type\":\"content-builder\",\"plain_text\":\"<p class=\\\"test\\\">Test</p>\",\"squares_json\":\"{\\\"containers\\\":[{\\\"id\\\":\\\"sq-container-293021\\\",\\\"settings\\\":{\\\"elements\\\":[{\\\"settings\\\":{\\\"name\\\":\\\"Paragraph\\\",\\\"iconClass\\\":\\\"fa fa-paragraph\\\"},\\\"options\\\":{\\\"text\\\":{\\\"text\\\":\\\"<p class=\\\\\\\"test\\\\\\\">Test</p>\\\"}}}]}}]}\"}}]}";
console.log(JSON.parse(myJSON)); // this is an actual object
The key here is to examine the point of entry where this JSON arrives in your system. I suspect some AJAX request has created some object and rather than sending valid JSON Of that object, it is sending instead an escaped string of a JSON object.
EDIT:
Here's a simple example of what happens when you have too many encodings. Try running this JS in your browser and observe the console output:
var myObj = {"key":"here is my value"};
console.log(myObj);
var myJSON = JSON.stringify(myObj);
console.log(myJSON);
var doubleEncoded = JSON.stringify(myJSON);
console.log(doubleEncoded);
I try to parse this page : http://fr.hearthhead.com/cards to get the hearthstoneCards JS variable.
So i do something like this :
$url = 'http://fr.hearthhead.com/cards';
$content = file_get_contents($url);
preg_match('#var hearthstoneCards = (.*)}]\;#Us', $content, $out);
$out = $out[1].'}]';
$tab_id_card = json_decode($out,true);
I try every tricks i could find (trim, stripslashes, preg for BOM and other things, put flags on json_decode and many other things), but i didn't get this working.
If i file_put_contents the $out var and compare to the real source it's the same thing (same length). If i put the string on a JS console, i get the data. But PHP don't want to parse this var :(
Some one got an idea ? :)
The problem is that you assume that code is JSON, when it's really full-fledged JavaScript. Within that code, many unquoted repetitions of the property name popularity occur, which is fine JavaScript but invalid JSON.
I tried to build a regex to fix any unquoted property names. Problem is, it's infeasible. In my case, any colons inside values broke my regex.
Short of writing a parser to fix such nonconformities or invoking a JS interpreter (which would require an external dependency such as V8Js), I think you'll be fine with fixing this specific scenario for now:
$url = 'http://fr.hearthhead.com/cards';
$content = file_get_contents($url);
preg_match('#var hearthstoneCards = (.*)}]\;#Us', $content, $out);
$out = str_replace('popularity', '"popularity"', $out);
$out = $out[1].'}]';
$tab_id_card = json_decode($out,true);
If you worry about future introduction of new unquoted properties, you can check $tab_id_card for NULL and either log the error somewhere you routinely check or even go as far as somehow firing a notification for yourself. Although I'd do it, I'd say it's not a likely scenario, due to all the other properties being correctly quoted.
I have a script I want to obfuscate or encrypt to hide from competition viewing the source code. I have found simple JS obfuscators but the issue with my script is I have PHP echoing variables into the JavaScript. The PHP is echoing strings and true/false.
Here is a piece of the JavaScript with PHP in it.
function redirect() {
var r = <?php echo $rvar; ?>;
if (r) {
window.location = prepare("<?php echo $redirect; ?>");
}
}
Can someone tell me what I can do to hide my JavaScript but be able to dynamically build the JS with PHP?
The only time I have ever wanted to obfuscate code is when I have been utterly ashamed of it. Retrospectively, I would probably obfuscate everything I have ever written. If protecting source is integral to your well-being, consider a shift to desktop programming.
Nevertheless, if there is one thing experience and memory has afforded me, it is that any serious newcomer to this field will stubbornly move forward with their own ideas, regardless of how bad it is, how much it grinds against commonsense and best practice, or how much a thread poo-poos all over the question. If you keep at it, hindsight will generously remind you of this period--cringes and all; the chastisements of a few strangers will pale in comparison, so I will give you one possible answer.
Use PHP's output buffering controls. You will want to start output buffering at the top of the script that will output all the JavaScript. This will capture everything into the buffer, which can then be assigned to a simple variable. This variable will contain everything that was supposed to be echoed out to the page immediately, but was instead captured and saved into the variable. This variable is just a regular string. Pass it to one of those JS obfuscators you found. This assumes it is done with PHP and is a PHP library for doing that. When it is obfuscated, echo it out. That is it. Here is an example:
<?php
// Start output buffering.
ob_start();
?>
function redirect() {
var r = <?php echo $rvar; ?>;
if (r) {
window.location = prepare("<?php echo $redirect; ?>");
}
}
<?php
// Get all the output captured in the buffer, and turn off output buffering.
// This will be a string.
$js_source = ob_get_flush();
// Obfuscate the $js_source string, by passing it to the obfuscator
// library you found.
$obfuscated_js_source = obfuscator5000($js_source);
// Send the source code to the browser by echoing it out.
echo $obfuscated_js_source;
I'm not sure why this isn't working, as a lot of the examples on the internet suggest doing it this way. Anyway, I have a SQL result that I've converted to JSON and now I'm trying to use that with Javascript.
json_encode($test, true); ?>
<script type="text/javascript">
var obj = (<?php echo $test; ?>);
alert(obj.toSource());
</script>
This does not work and Chrome gives me an error of "illegal character" and the Javascript variable somehow displays some x-debug HTML from the PHP server:
If I simple echo the JSON out to display on the webpage that works fine without any errors. What am I doing wrong?
Do it like this:
$test = json_encode($test, true);
json_encode doesn't change the variable in place.
You're doing a couple of things wrong here..
json_encode($test, true);
I think you're probably thinking of json_decode, but the second parameter to json_encode is supposed to be a bitmask of options. Passing true here is probably wrong.
#ElmoVanKielmo is also correct, the variable doesn't change because you call a function, you must reassign the variable to the return value.
You got hmtl that looks line an xdebug error/notice message. Fix that before you proceed! (You cut out the part where the message is put).
Additionally you do not encode $test correctly. json_encode returns the changed value and does not modify it by reference.