Create object from text - javascript

I have javascript text:
var textObject = '
{
news: [
{
"title":"aaa",
"desc":"bbb"
}, {
"title":"ccc",
"desc":"ddd"
} ]
};
'
but this is in text in my variable. If i have this in code html this working ok, but i get this data with ajax from PHP script.
So how can i convert/parse this text to object? If i have JSON then i can use JSON.parse(textObject); but this isn't json.

Eval is frowned upon for a lot of reasons, however it also has its benefits if used properly, it is used for a lot of template engines and a few other things but it will convert a string to an object.
var someString = '{obj: "with content"}';
eval( someString );
Here is a working example with your string: http://jsfiddle.net/kkemple/CwzRh/

Using eval can result in serious performance degradation.
Since you can't do JSON, then use the Function constructor instead so that the evaling takes place in the global scope, and the browsers can still optimize the local code.
var result = new Function("return " + textObject.trim())();
You'll need to shim .trim() to support IE8. If the string is as you show with line breaks at the beginning, then the .trim() will be necessary.

Related

Why declaring a simple JSON object into a JavaScript script executed into Rhino is not working?

I am not so into JavaScript. I am using JavaScript to develop a litle script working on a JSON document. This JavaScript script is not executed into the browser but ino another product that allow to use JavaScript to script some tasks (the prodcut is WSO2 ESB but it is not important at this time).
This product (WSO2 ESB) uses Rhino as JavaScript engine, used to implement JavaScript scripts into Java application.
I have some problem trying to create a simple JSON object in this kind of environment.
I have done something like this (into my WSO2 ESB code):
<script language="js">
<![CDATA[
var response = JSON.parse(`
{
"forecast": []
}
`);
]]>
</script>
Using the same code into a classic JavaScript file performed into the broswer it works fine but it seems that it can't work using Rhino. I obtain error relating an illegal character (I also tryied to replace the ` and ` with " and " and with ' and ' but I still obtain error).
Something like this in the Java Stacktrace:
Caused by: javax.script.ScriptException: org.mozilla.javascript.EvaluatorException: illegal character (<Unknown Source>#9)
at com.sun.phobos.script.javascript.RhinoScriptEngine.compile(RhinoScriptEngine.java:341)
at com.sun.phobos.script.javascript.RhinoScriptEngine.compile(RhinoScriptEngine.java:323)
at org.apache.synapse.mediators.bsf.ScriptMediator.initInlineScript(ScriptMediator.java:399)
... 32 more
What could be the problem with Rhino? I think that the problem could be related to the `` character that maybe have to be escaped in some way. Some idea?
Or another something more pure JavaScript workaround solution could be: is it possible declare a JSON object like this:
{
"forecast": []
}
in a different way? I mean in a programmatically way without explicitly declare it.
This works in modern browsers that support ES6 with template literals:
var response = JSON.parse(`{"forecast": []}`);
Why, because JavaScript solves the back ticks first as a template and fills them with the content of the variables before the JSON string is parsed:
var test = "Cloudy";
var string = `{\"forecast": ["${test}"]}`;
var response = JSON.parse(string);
console.log(response);
But maybe your Rhino build has no ES6 support, so that won't work. Also the multiline is causing problems:
var response = JSON.parse(''+
'{'+
' "forecast": []'+
'}'
);
console.log(response);

ES2015 template strings security issue

Here's a quote from MDN:
Template strings MUST NOT be constructed by untrusted users, because they have access to variables and functions.
And an example:
`${console.warn("this is",this)}`; // "this is" Window
let a = 10;
console.warn(`${a+=20}`); // "30"
console.warn(a); // 30
The example here doesn't show any vulnerabilities I can see.
Can anyone give an example of an exploit that takes advantage of this?
This makes no sense. A template string doesn't have access to anything, it is not executed either. A template string is a syntactical element of the language.
Dynamically constructing a template string is no problem therefore - it's like building an expression (in whatever format, be it a code string or an AST). The problem MDN hints at is with evaluating such an expression (e.g. using eval, serialising it into a script that is served to the user, etc.) - it may contain arbitrary code, in contrast to a string literal! But of course you wouldn't do that anyway, would you?
This warning is like saying "Concatenations using the + operator must not be constructed by untrusted users, because they have access to variables and functions." and giving the example "" + console.warn("this is",this) + "" for it. Well, this is true for any expression of the language, so it's not particularly interesting.
While we are talking about crappy coding, there is of course a scenario where using template strings (hey, they're multiline and whatnot) instead of string literals can lead to problems:
function escapeString(str) {
return JSON.stringify(str).slice(1, -1)
.replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
}
// This is (kinda) fine!
var statement = 'var x = "Hello,\\n'+escapeString(userInput)+'";';
eval(statement); // some kind of evaluation
// But this is not:
var statement = 'var x = `Hello,\n'+escapeString(userInput)+'`;';
// ^ ^
Now imagine userInput contains a ${…} - which we did not escape…
I think #Bergi is correct - the danger here involves using eval or similar methods to allow a user to construct the actual template string, not the substitutions.
Example exploit: A lazy developer wants to allow users to perform some string substitutions in their comments, e.g. to reference other users or questions, on a site like SO. Instead of developing tokens for this and then doing appropriate parsing and substitution, he decides he'll accept syntax like this:
"I think ${firstPoster} is an idiot! See ${question(1234)} for details!"
and run it through a function like this:
var firstPoster = {...};
function question() {...}
processInput(input) {
return eval('`' + input + '`');
}
If this code is eval'd on the client and shown to other users, a malicious user could inject an XSS attack. If it's eval'd on the server, the attacker could take control of the machine.
The example no longer seems to be in the MDN docs. As Bergi's answer points out, the given example doesn't seem to highlight anything special about template strings.
However, when it comes to building strings from objects, there is a particular security concern you should definitely be aware of:
The toString() method will be called implicitly on a non-string object if it is passed to a string interpolation / concatenation expression.
There are probably also other cases where toString() is called implicitly. But string interpolation seems to me to be one of the most common ones; indeed, it's one I experience regularly. For example, suppose you somehow receive an object from somewhere external e.g. via an iframe through postMessage. In that case, you might want to do something like log the message received to the console - and you might be tempted to just pass the object right into an interpolated string.
But the sender (possibly an attacker) has full control over the definition of toString() and can insert whatever code they like in there. So as soon as you pass that object to the interpolated or concatenated string, you are vulnerable as long as someone else controls the definition of said object.
Here is a simple example (added to codesandbox), showing that even if objects return seemingly harmless strings in toString(), they can indeed do dangerous stuff like read you local storage:
import "./styles.css";
localStorage.setItem("secret1", "sssh! One");
localStorage.setItem("secret2", "sssh! Two");
const evilObject1 = {
toString() {
alert("I stole a secret: " + localStorage.getItem("secret1"))
return "I'm innocent";
}
};
const evilObject2 = {
toString() {
alert("I stole a secret: " + localStorage.getItem("secret2"))
return "I'm innocent";
}
};
const strInter = `Seemingly innocent object, interpolated: ${evilObject1}`;
const strConcat = "Seemingly innocent object, concatenated: " + evilObject2;
let p = document.createElement("p");
p.innerHTML = strInter
let p2 = document.createElement("p");
p2.innerHTML = strConcat
document.body.appendChild(p);
document.body.appendChild(p2);
With Javascript, being duck-typed, this is quite a real vulnerability, because you might think that the object you receive (e.g. via postMessage) is a string, and indeed, it may behave like a string (because it has a cleverly designed toString() method), but unless you dynamically check the types you don't know if you actually got a string.
If you're expecting a string, you can fix the above vulnerability as follows:
const sanitized1 = typeof evilObject1 === 'string' ? evilObject1 : "BAD OBJECT1"
const sanitized2 = typeof evilObject2 === 'string' ? evilObject2 : "BAD OBJECT2"
const strInter = `Seemingly innocent object, interpolated: ${sanitized1}`;
const strConcat = "Seemingly innocent object, concatenated: " + sanitized2;
With this fix, you avoid implicitly calling toString() on an unsafe object. Either the objects you got were strings, and those will be used, or else they weren't, and you'll get the "BAD OBJECT" text instead.

Eval doesn't work - JavaScript

I've never used eval() before, so I assume that I just got the syntax horribly wrong. What's wrong with the following:
var JSONAsString = '{"item1":"one", "item2":"two", "item3":"three"}';
var JSONAsObject = eval(JSONString);
alert(JSONAsObject.item1);
Since it doesn't seem to be working - I load the page and nothing happens.
And yes, I know I shouldn't be using eval. I assume that the syntax for JSON.parse() is the same as that of eval... right? If it is, if (after fixing the code) I replace eval with JSON.parse, will it still do the same thing?
When using eval you need to wrap the JSON in ():
var JSONAsString = '{"item1":"one", "item2":"two", "item3":"three"}';
var JSONAsObject = eval('(' + JSONAsString + ')');
alert(JSONAsObject.item1);
However, you should use JSON.parse() right from the beginning, not just later. Otherwise possibly invalid JSON that is valid JavaScript might work but stop working when switching to JSON.parse.
Note that you should include json2.js when using JSON.* since some older browser do not have native JSON support.
Don't use eval() to parse JSON. Use Douglas Crockfords json2, which gives you cross-browser support, performance and security: https://github.com/douglascrockford/JSON-js

JSON mapping in Javascript

So I have this JSON
https://bitcoinpayflow.com/orders{"order":{"bitcoin_address":"1NwKSH1DJHhobCeuwxNqdMjK5oVEZBFWbk"}}
No I want to reference the bitcoin_address
So first I strip away the string at the beginning
var stripped = data.substring(33);
alert(stripped);
var btc = stripped.orders.bitcoin_address;
alert(btc);
I get the first alert, but not the second. Any idea why?
Because stripped is still just a string. You need to parse it into an object. You can use the native JSON.parse method to do this:
var stripped = JSON.parse(data.substring(33));
Also, you are referencing the orders property, which doesn't exist. It's order.
Note that JSON.parse is not supported by older browsers. You can use this polyfill to make sure it's always available.
The easiest way to decode json - string - use eval
var bitcoins = eval('(' + json_string + ')');
And access bitcoins['order']['bitcoin_address']
But it a bit unsafe. Upper method is more safer.
I would use JSON.parse as follows.
$.post('php/whatever.php',{data:dS},function(res){
var o=JSON.parse(res);
var bitcoins=o.order.bitcoinaddress;
},"text");

Is using eval() for data from ONLY server-side safe? (and if not, alternatives please)

I'm creating a website where I'm doing ajax requests to load some dynamic content AFTER I load a static container page. Basically, I need to pass an array of integers to the page from the server, and I'm using jQuery to load data. I am writing the ints inside a tag with a know name, and using eval to read data from it. Here's a sample tag (returned from ajax):
<span runat="server" class="hidden" id="PhotoList" />
with the codebehind list.ForEach(p => { sb.Append(p.ID.ToString() + ","); } ); where sb is a StringBuilder, so the server as a result returns something like:
<span runat="server" class="hidden" id="PhotoList">1,4,5,42,9</span>
I have a variable photoList declared in the javascript, and I call var scriptToEval = "photoList = [" + $("#PhotoList").html() + "];";
eval(scriptToEval);
I am not a master of Javascript and I just want to be sure that this is safe, as there's lots of discussion on whether eval is safe or not. I THINK this is safe (the ones I've pasted is all the code I'm using with eval), but I may have missed a point, so a professional's opinion is important for me. I know why they say eval is dangerous, as it is capable for interpreting any code, malicious or not, but here, I think this way cannot be compromised at all, as the response from the server is completely under my control. Another option would be making ANOTHER ajax call for the variables and load them directly without ajax from the returned array, but thay would sum to two calls, (I already make the load call anyway as it really loads some HTML content from the server) but this way, even though a bit hacky (putting variables into a hidden HTML tag), seems convenient (and ASP.NET also does this for viewstate too after all!).
My focus is on eval anyway, is this perfectly safe, or should I have some security considerations? Javascript experts please.
If you can be sure that the data is secure, then eval() will be harmless enough.
If you're not so sure, you can use JSON.parse() to take care of it:
var arr = JSON.parse( "[" + $("#PhotoList").html() + "]" );
For browsers that don't support JSON, you can include the json2 library.
Another possibility is to do a split() the loop the items, converting them to numbers from strings.
var arr = $("#PhotoList").html().split(',');
for( var i = 0, len = arr.length; i < len; i++ ) {
arr[i] = parseInt( arr[i], 10 );
}
EDIT: Since you're using jQuery, if for some reason you really don't want .eval(), then use the jQuery.parseJSON()[docs] method.
var arr = jQuery.parseJSON("[" + $("#PhotoList").html() + "]");
EDIT 2: Another way to do it would be to use .replace(), passing a function as the replace value. This will take care of the iteration for you.
var arr = [];
$("#PhotoList").html().replace(/\d+/g, function( s ) { arr.push( parseInt(s,10) ); });
...so many ways to do it.
Of course it's not safe. It's quite easy to stop the code using a debugger and change the content of the element or the variables that script uses.
What you have to consider is what you use the data for. If someone changes the data, can it be used to access something that should not be available, or can it be used to corrupt any data on the server?
If changing the data only affects what's shown on the page, then it's not a problem that the data can be changed.
Safe, yes, assuming your server is secure. Generally the only time you want to truly avoid using eval() is when users are able to add code which other users can see. Like you'd never ever want to use eval() when displaying a forum post, etc. If the code is coming from your server, or if the user's input is only being displayed back to himself/herself, eval() is fine. This is essentially what jsfiddle does.
Code
var result = eval(code);
May change with
var result = new Function('return '+code+');
While you can use eval in this case, I'd still not recommend it, due to the many subtle bugs and performance issues it can generate. It is almost never a good idea to use eval!
Also, it is just as possible to do what you want without eval:
1 - For setting a global variable, instead of using eval you can use the global scope object. All the following are equivalent if myList is a global variable:
myList = [1,2,3];
window.myList = [1,2,3];
window['myList'] = [1,2,3];
2 - For obtaining the array elements you can use the .split() method from strings:
node.innerHTML.split(',')
3 - If you want to convert a string to a number one of the simple ways is to use the unary + operator:
+"3" // is the number 3

Categories

Resources