102

My Spider Sense warns me that using eval() to parse incoming JSON is a bad idea. I'm just wondering if JSON.parse() - which I assume is a part of JavaScript and not a browser-specific function - is more secure.

totymedli
  • 29,531
  • 22
  • 131
  • 165
Kevin Major
  • 1,023
  • 2
  • 8
  • 4
  • Performance wise, `JSON.parse` is faster than `eval`, at least in V8 (Chromium's JS engine). [Source](https://v8.dev/blog/cost-of-javascript-2019#json). – Paul Nov 23 '19 at 21:03

6 Answers6

118

You are more vulnerable to attacks if using eval: JSON is a subset of Javascript and json.parse just parses JSON whereas eval would leave the door open to all JS expressions.

Eonasdan
  • 7,563
  • 8
  • 55
  • 82
jldupont
  • 93,734
  • 56
  • 203
  • 318
  • 7
    Sorry, Matheus, I have to agree. The problem is when you are using eval() to interpret "user input" - which is ANY source external from your JavaScript (including returned values from servlets or other web services you've called). You cannot guarantee users have not entered malicious JavaScript either directly into your client app, or indirectly because of unvalidated data stored in the server's database and then passed on to your program via an AJAX-style call. You may still need to validate individual fields to avoid "confused deputy" attacks, but using JSON.parse is a good first step. – JackLThornton May 10 '17 at 19:54
  • 2
    @Hydro Short proof of concept: try `eval('alert(1)');`. – Valerio Bozz Feb 20 '18 at 11:33
41

All JSON.parse implementations most likely use eval()

JSON.parse is based on Douglas Crockford's solution, which uses eval() right there on line 497.

// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

j = eval('(' + text + ')');

The advantage of JSON.parse is that it verifies the argument is correct JSON syntax.

dtheodor
  • 4,894
  • 3
  • 22
  • 27
plodder
  • 2,304
  • 18
  • 19
  • 62
    yeah, except that the line right before that verifies that it's a safe and valid string. – nickf Apr 20 '10 at 22:56
  • 8
    I tested `JSON.parse()` in Firefox 28 and Chromium 33 on my Linux Mint system. It was 2x as fast as `eval()` in Firefox and 4x as fast in Chromium. I'm not sure what source code you're posting, but they're not the same thing in my browsers. – jbo5112 Apr 22 '14 at 02:59
  • @plodder "advantage" probably is not cheap to do that verifying. – mjs Mar 24 '15 at 14:21
  • 5
    [Modern browsers](http://www.w3schools.com/json/json_eval.asp) provides native `JSON.parse()` implementation which is safer and faster than `eval()`-based parsers. – Mohammad Alhashash Jun 13 '16 at 10:39
15

Not all browsers have native JSON support so there will be times where you need to use eval() to the JSON string. Use JSON parser from http://json.org as that handles everything a lot easier for you.

Eval() is an evil but against some browsers its a necessary evil but where you can avoid it, do so!!!!!

AutomatedTester
  • 22,188
  • 7
  • 49
  • 62
11

There is a difference between what JSON.parse() and eval() will accept. Try eval on this:

var x = "{\"shoppingCartName\":\"shopping_cart:2000\"}"

eval(x)         //won't work
JSON.parse(x)   //does work

See this example.

Jeff Lowery
  • 2,492
  • 2
  • 32
  • 40
  • 1
    eval doesn't work because it parses strings as code statements and thus, consideres "{...}" as a code expression instead of a value declaration expression. if you remove the ambiguity ("[{....}]" for example), there is no doubt on the nature of the expression and eval will creates an array containing the parsed objet – Charles HETIER Nov 25 '14 at 09:50
  • 1
    Yes. Traditionally, x would be wrapped by parentheses: eval("("+x+")"). What I said still stands: there's no ambiguity when using JSON.parse(). – Jeff Lowery Nov 25 '14 at 18:51
9

If you parse the JSON with eval, you're allowing the string being parsed to contain absolutely anything, so instead of just being a set of data, you could find yourself executing function calls, or whatever.

Also, JSON's parse accepts an aditional parameter, reviver, that lets you specify how to deal with certain values, such as datetimes (more info and example in the inline documentation here)

David Hedlund
  • 128,221
  • 31
  • 203
  • 222
4

JSON is just a subset of JavaScript. But eval evaluates the full JavaScript language and not just the subset that’s JSON.

Gumbo
  • 643,351
  • 109
  • 780
  • 844
  • Right, I know that. Are you implying that JSON.parse() ONLY evaluates JSON and fails on all other incoming data? Or is it simply a wrapper for: var myObject = eval('(' + responseText + ')'); ?? – Kevin Major Dec 03 '09 at 22:21
  • 7
    @Kevin Major: Yes, the natively implemented `JSON.parse` (directly implemented into the JavaScript engine) parses only JSON. But other non-natively implementations use do some sanity checking and then use `eval` for performance reasons. – Gumbo Dec 03 '09 at 22:33