Would you consider this JSON.parse behaviour to be a vulnerability - javascript

If you evaluate the below Javascript snippet it will pop an alert box.
JSON.parse('{"sometext'-alert(document.domain,document.URL)-'":"somevalue"}');
the fix would to make sure that the string if coming from an untrusted source is to be sanitized/escaped.
However I would have the JSON.parse method just error out saying that this is not a valid JSON string.
Why is that code being executed.

You can't cause that behavior if your starting point is a string. Your starting point is JavaScript code, and what you have just uses JavaScript code in the process of creating a string, exactly like this with no JSON in sight:
const str = '"sometext'-alert(document.domain,document.URL)-'"';
So no, there's no JSON-based vulnerability here. If you're running code you get from elsewhere, that's the vulnerability.

Related

Check if a string contains executable code in JavaScript?

I have an Android app that runs my code(which is a JS bundle) in a hidden webview. I make API calls through native code using a JS interface. The response is sent back to a function through the evaluetJavascript method of the webview. The concern here is somehow a malicious response is received which might execute arbitrary JS in my webview. I am base-64 encoding the result before calling the evaluateJavascript and once it reaches the JS, I just decode it and parse the JSON and then it's just a string value which gets used further.
I have 2 questions:
(1) Since I am not using eval() anywhere in my JS code, is my understanding correct that even if a code gets through, it won't ever execute?
(2) I have been asked to still validate the data. Is there any way to detect if a given string contains executable JS code? I thought of looking for characters like ;"'() etc. but have concerns that my data may contain parentheses and that a stringified JSON will have quotes anyways. I am worried about false positives. What will be a better approach for this?

Safely pass object to client in Node.js/express

A common question is how to pass an object from Node.js/Express.js to the browser. It's possible to do that using JSON stringify, but if the object contains user-provided data, that can open the door to script-injection and possibly other attacks.
Is there a downside to the approach mentioned in this link using Base64?
https://stackoverflow.com/a/37920555/645715
Related links:
Passing an object to client in node/express + ejs?
How to pass a javascript object that contains strings with quotes from node.js to the browser?
Pass a NodeJS express object to AngularJS 1.6
Passing an object to client in node/express + ejs?
Using Base64 encoding does solve the immediate problem of passing back an injection attack, but it doesn't necessarily solve the issue of having a possible injection attack floating around out there. For example, this fiddle shows that it does prevent the immediate issue : https://jsfiddle.net/9prhkx74/
var test2 = JSON.parse(window.atob('PC9zY3JpcHQ+PHNjcmlwdD5hbGVydCgndGVzdDInKTwvc2NyaXB0PjxzY3JpcHQ+'));
This won't show an alert box, it'll just throw an error about invalid JSON. But if you change it to the literal string, it'll show the alert box (injection vulnerable)
var test2 = JSON.parse("</script><script>alert('test2')</script><script>")
Now if you are immediately parsing it to a JSON object, it'll blow up, and everything will be "safe". But if you assign it to a value because you are going to pass it around some more etc, you still have a potential issue out there.
Instead of putting a bandaid on the injection itself, I'd suggest fixing it in the first place and properly escaping data before passing it back to the client or processing it on the server side.
There are plenty of libraries that can help do this
https://www.npmjs.com/package/sanitize
https://www.npmjs.com/package/express-sanitizer
Here's a pretty good article that kind of highlights why it is important to sanitize and not just just patch over potentially malicious data : https://lockmedown.com/5-steps-handling-untrusted-node-js-data/

Accurately unescape HTML entities in javascript

In javascript, I need to take a string and HTML un-escape it.
This question over here asks the same question, and the most popular answer involves populating a temporary div.
I've used this as well, but I think I've found a bug.
Simple example, correct behavior
If you have this string: Cats>Dogs
Unescaped, it should be: Cats>Dogs
Malformed example, wrong behavior
If you remove the semicolon and use this instead:Cats&gtDogs
You will get this as a result: Cats>Dogs
Isn't that wrong?
This struck me as odd. From what I understand, an escaped string requires the presence of a terminating semicolon, otherwise it's not escaped. After all, what if I had a store called guitars&amps? For all we know, this company exists but gets no business because it causes null reference exceptions everywhere it has records.
Any ideas on how I could perform escaping while knowingly avoiding escaping when the semicolon is missing? Currently, all I can think to do is perform the unescaping myself.
(The WYSIWYG preview in StackOverflow exhibits a similar unusual behavior, by the way. Try entering &ampgt;, this renders as >!)
Isn't that wrong?
Successful HTML parsers are tolerant. This is one of the things distinguishing them from, say, XML parsers. They don't necessarily stick to strict rules about markup, for the simple reason that there's a lot of incorrect markup out there. So they try to figure out what the markup is meant to represent. &gtDogs is more likely to mean >Dogs than &gtDogs, so that's what the parser goes with.

Illegal characters in JSON response

I have a Sencha Touch app. One of the stores I have uses an ajax proxy and a json reader. Some of the strings in the JSON returned from my sinatra app occasionally contain this character:
http://www.fileformat.info/info/unicode/char/2028/index.htm
Although it's invisible, the character occurs twice in the second string here, between the period and the ending quote:
"description": "Each of the levels requires logic, skill, and brute force to crush the enemy.

"
Try copy and pasting "Each of the levels requires logic, skill, and brute force to crush the enemy.

" into your javascript console! It won't be parsed as a string, and fails with SyntaxError: Unexpected token ILLEGAL.
This causes the JSON response to fail. I've been stuck on this for a long time! Any suggestions?
The only reliable way to fix this is server-side. Make sure your JSON generator emits those characters escaped, e.g. as \u2028.
In my experience, it's easiest to simply encode your JSON in plain ASCII which will always work. The downside is that it's less efficient as non-ASCII characters will take up more space, so depending on the frequency of those, you may not want that trade-off...
The documentation for Perl's JSON::XS has a good explanation of the problem and advice for how to fix it in Perl:
http://search.cpan.org/perldoc?JSON::XS#JSON_and_ECMAscript
Conceptually you are only allowed to send out strings from the server that are valid JavaScript literals by escaping appropriately.
If you want to fix this issue on the client you need an extra workaround step (only seems to work in Firefox):
var a = escape("Each of the levels requires logic, skill, and brute force to crush the enemy.");
alert(unescape(a));
But the discussion is obsolete, because you must escape on the server.
Avoid using eval to parse JSON.
Use JSON.parse or https://github.com/douglascrockford/JSON-js.
JSON.parse('{}'); // where {} is your JSON String

JavaScript JSON parser that tells error position

I've been having some troubles with parsing JSON that is received with WebSocket (original question - Parse JSON received with WebSocket results in error). The JSON string itself is valid (tested with several JSON validators), but JSON.parse throws an exception. I am trying to figure out what is it exactly that it cannot parse, but the only thing I'm getting is "SyntaxError: unexpected_token ILLEGAL", it doesn't say where is the exact position of the failed token. Is there any way of extracting such information?
Update: If I copy-paste that JSON string to a static file (e.g. "data.json") and then retrieve it and parse it with the same function (JSON.parse) - then it works fine.
So I'm assuming there's something tricky going on, I thought of newline symbol (may be there was \n instead of \r\n or vice versa) but completely removing all the line breaks didn't help. I would think that it very well may be an encoding problem, but the data is received via websocket and according to documentation it's utf-8 string.
2nd Update: IT WORKS just fine if I use "json_parse" from here: https://github.com/douglascrockford/JSON-js/blob/master/json_parse.js
Then it works fine! Does that mean this is a bug in "JSON.parse" implementation used by Chrome or what?
Thank you.
You could copy an implementation of JSON.parse() from somewhere (like out of jQuery), change it's name so you can call it directly, tweak the implementation so that it never detects the built-in parser so it always uses the JS parser and then change your code to use the new JS version of the parser, then trace through it in a javascript debugger until you find what it doesn't like.
One thing to check is if you have quotes and slashes within your JSON string. If yes, they need to be escaped:
{
"key": "i've \"quotes\" in me",
"key2": "and \\slashes too"
}
Also, JSONLint gives you the exact location of the error.
As per JSON.org, you cannot have quotes and slashes in your strings, so you need to escape them.
I think you don't need to call JSON.parse:
JSON.parse({"key": "whatever"}) // Syntax Error ILLEGAL
because it's already an object. I would also be curious to see the result of the following code:
eval("(" + json + ")");
Or
JSON.parse(decodeURIComponent(json));
Can't tell much with the details, but the possibility may be that your validator is doing non-strict parsing and your javascript may be doing strict parsing...

Categories