JavaScript JSON parser that tells error position - javascript

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...

Related

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

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.

escaped backslash coming out as "\\" in string

So while working on one of my first Node.js projects utilizing the file system I came across some behavior that stumped me. I had read that in JS when you need to put backslashes in a string you have to add an extra backslash to escape it. Even the text formatting on here on Stack Overflow is doing it correctly.
Example:
let str = "dir1\\file.txt" /* used two '\\' */
This made perfect sense to me. However when I print these strings to the console in Node.js they still appear to have that extra backslash still present. I did however test this on the browser console and it seems to be working fine. Why does this not work for Node.js? Does Node.js for some reason just not follow this JavaScript convention?
The personal project I've been working on has come to a complete stop for the past few days as a result of this confusion. So any clarity on this this would greatly help.
console.log functions give you debugging information. Different implementations of console.log are different. There is no standard which describes how they should represent a string.
Often they provide representations of strings that include escape characters in the visible output.
If you want to see the processed value of the string in Node, then write to STDOUT.
process.stdout.write("Your \\ string");
The string contains only one backslash regardless.
When you output a string in the Node.js console directly, it shows the string's contents. For example,
console.log("testing\\123");
outputs
testing\123
But when you output something like an object, Node.js shows a representation of that object, and in that representation, it shows the strings in string literal format. For example,
console.log({example: "testing\\123"});
outputs
{ example: 'testing\\123' }
Note the ' around the string literal, and the fact the backslash is escaped.
There's only one backslash there, it's just that it's showing you the string in string literal notation.
Browser consoles vary in how they show those two examples. For instance, Chrome's console shows them like this (at present, v72):
Chrome's console output for the second example is (to my mind) rather more confusing than Node.js's output, because although the string is shown in quotes, it's not a string literal. It's just the string contents. (I would much prefer it showed a string literal, or failing that, didn't show the string in quotes. What it does is a distant third choice in my view.)
This is purely a difference in how the consoles show the string. The string is the same in both cases: It has one backslash in it.

Why I use JSON.stringify in safari and chrome to stringify a json get different result?

I just simply to use JSON.stringify({"a": "123"}) to stringify a json
In chrome, the " semicolon will not be escaped, it will echo
JSON.stringify({"a": "123"})
"{"a":"123"}"
But if I use the same code in safari, the " semicolon will be escaped, like this
JSON.stringify({"a": "123"})
"{\"a\":\"123\"}"
I want to know the reason about why the chrome and safari have the different result
It's not about JSON.stringify, it's about how the console displays value literals.
Safari chooses to make the entire line a valid literal. I.e. you could copy-paste the entire line into Javascript source code, and it'd be valid.
Chrome opts to just add decorative "" marks around the line to signify that it's a string value, but displays only the string contents as-is, without making it into a valid literal.
The advantage of Safari's method is that you can copy-paste values as code, while Chrome's advantage is that you can read a string's contents without needing to mentally parse it according to string escaping rules.

Need less restrictive json parser

I need to pass different strings formatted as json to a json parser.
Problem is that jQuery.parseJSON() and JSON.parse() only support a very strict json format:
Passing in a malformed JSON string may result in an exception being thrown. For example, the following are all malformed JSON strings:
{test: 1} (test does not have double quotes around it).
{'test': 1} ('test' is using single quotes instead of double quotes).
Is there a less restrictive parser that will allow passing values like that (without quotes or with single quote)?
BTW, I'm using KO 2.2.1 so if it has something like that it would be helpful.
There is a node module called jsonic that parses non strict JSON.
npm install jsonic
You might also use eval:
var parsed = eval(json)
Be careful because eval could also run code so you must be sure that you know what you are parsing.
There is no such thing as a less strict JSON parser. You're either dealing with well-formed JSON, or you're not dealing with JSON at all. To parse your custom format, you may want to take a look at Crockford's parser source code, and modify it to fit your needs.
Or, for a quick and dirty solution you might just use eval (but be aware its use has security implications).

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

Categories