Improving jQuery’s JSON performance and security
AJAX, ASP.NET, JavaScript, jQuery By Dave Ward on July 7th, 2009When you’re working with JSON, performance and security are often opposing, yet equally important concerns. One of these areas of contention is handling the JSON strings returned by a server. Most JavaScript libraries do a great job of abstracting away the details, but the underlying process has long been a frustrating exercise in compromise.
On one hand, eval() is the fastest widely available method, but it is not safe.
On the other hand, textual JSON parsers written in JavaScript may be much safer, but are dramatically slower. In client-side situations, where milliseconds count, such a large performance overhead is typically too prohibitive to accept.
Recently, an exciting new alternative has emerged: browser-native JSON parsing. Integrating JSON parsing as part of the browser’s implementation of JavaScript allows for using the more secure parsing method, and even provides performance faster than eval() offers.
To take advantage of that, this post will show you how to detect whether or not a browser supports native JSON parsing, and how to force jQuery to use browser-native parsing in its $.ajax calls when it is available.
Native JSON parsing in the browser
Previously known as ECMAScript 3.1, ECMAScript “Fifth Edition” (the specification that JavaScript implements) formally codifies a native JSON parsing feature. The spec’s API exactly mirrors that of Crockford’s implementations of JSON.parse and JSON.stringify in json2.js, easing the transition to browser-native functionality.
This native JSON parsing brings marked improvements in terms of both security and performance. Not only does the native routine use textual parsing to avoid the risk of executing malicious code embedded within JSON, but it is also fast.
At the time of this writing, three major browsers already include support for native JSON parsing: IE8, Firefox 3.5, and Chrome 3.
Safari 4 does not currently support the standard, but its underlying engine (WebKit) has recently implemented it. Hopefully the feature will make its way to Safari soon.
Detecting native JSON support
Determining whether or not native JSON parsing is available within a given browser is the first problem we need to solve. To do this, we ultimately need to know if the JSON.parse function is defined.
We can’t test for JSON.parse directly because attempting to reference it will throw a JavaScript error if the underlying JSON object doesn’t exist. So, first we need to inspect the type of that underlying object itself:
if (typeof(JSON) === 'object') { // native JSON may be available. }
If we find that the JSON object does exist, it’s likely that native JSON parsing is available. However, it’s a best to double check the JSON.parse function as well:
if (typeof(JSON.parse) === 'function') { // native JSON parsing is available. }
Because JavaScript performs short-circuit evaluation, it’s safe to clean this up by combining both tests in a single conditional, as long as they’re in this order:
if (typeof(JSON) === 'object' && typeof(JSON.parse) === 'function') { // Native JSON parsing is available. }
Curious whether your browser supports native JSON parsing? Using the JavaScript above, I have determined that:
Extending jQuery to use native JSON parsing
In my previous post, I demonstrated how to use jQuery’s dataFilter to transform a JSON response before it is returned to the $.ajax() success handler. In the process, we also preempted jQuery’s default method for deserializing JSON data.
The focus at that time was implementing the same method for JSON parsing that jQuery uses by default, so eval() was still used. However, we can also use the same dataFilter mechanism to force browser-native JSON parsing instead.
Using our JSON parsing detection code and a dataFilter callback, upgrading jQuery to use browser-native parsing is simple:
$.ajax({ // Your usual $.ajax() URL, data, dataType, etc. dataFilter: function(data) { if (typeof (JSON) !== 'undefined' && typeof (JSON.parse) === 'function') return JSON.parse(data); else return eval('(' + data + ')'); } });
Because jQuery only attempts to deserialize JSON responses if their type is string, and because the dataFilter callback executes before jQuery would normally perform that deserialization, this technique preempts jQuery’s JSON evaluation completely. In the worst case, it will simply revert back to the same eval() method that jQuery internally uses by default anyway.
Note: It’s important to keep in mind that the dataFilter will run regardless of what type is actually returned from the server. You should only use this when you’re sure that you’re receiving a JSON string.
Conclusion
If you’ve been paying close attention to jQuery’s ongoing development, you may already know that jQuery 1.3.3 will provide functionality very similar to what I’ve shown you. I decided to go ahead and write this post anyway for a few reasons:
- You can use this today, without waiting for jQuery 1.3.3.
- You can use this in previous versions of jQuery, if upgrading isn’t feasible for you (as is often the case with plugins dependent on older versions).
- If you use my technique for isolating your code from ASP.NET AJAX’s “.d”, you will still need a method for deserializing JSON in the dataFilter.
Speaking of that last point, if you’re using jQuery with ASP.NET AJAX services, be sure to watch out for the next post in this (accidental) series. There is at least one more productive step left in improving this workflow that I have been using in my projects and want to share with you soon.
Possibly related posts
What do you think? Your comments are welcome.
I appreciate all of your comments, questions, and other feedback, but please try to stay on topic. If you have a question unrelated to this post, I recommend posting on the ASP.NET forums or Stack Overflow instead.
If you're replying to an existing comment, please use the threading feature. To do this, click the "Reply to this comment" link underneath the comment you're replying to.
11 Mentions Elsewhere
- DotNetBurner - jQuery
- DotNetShoutout
- IT BLOG - Improving jQuery's JSON performance and security | Encosia
- Wayne State Web Communications Blog » Blog Archive » [Friday Links] The HTML5 Edition
- Interesting Finds: 2009 07.06 ~ 07.12 - gOODiDEA.NET
- 網站製作學習誌 » [Web] 連結分享
- JavaScript 101 « Ybbest’s Weblog
- making json ajax requests more secure - tsuuhou
- Techwave » Blog Archive » jQuery FTW (August 1)
- Creating a Webservice Proxy with jQuery « Life of a geek and a part-time poet
- » Improving jQuery’s JSON performance and security | Encosia - Yee Torrents News 4


could you share security issues for jQuery with more detail please ?
what shall we do prevent javascript attacks especially server side requests ($.ajax) ?
thanks
Very nice article, thanks for sharing your experience :)
Nice article. Thanks for the info.
Could you not load the JSON script if the function didn’t exist in the browser? A method like this may work.
Then you would avoid using eval() at all.
json2.js actually uses eval() in the end (though it does attempt to sanitize the string a bit first).
At the end of the day isn’t that what the browser versions will be doing?
In fact, I think the browser versions are really just built in implementations of json2.js
The browsers will be implementing it as a true parser, more like json_parse.js does. Interpreted JavaScript is currently too slow to use that in most cases, but the algorithm performs fine when implemented in compiled browser code.
By contrast, eval() literally executes the code as a JavaScript statement.
For example, try using eval() and then browser-native JSON parsing on this JSON string:
Thks for the information was really good for do the things than I was looking for, I wait for look something new in your page. congratulations !
Oh man you scared me for a second. I’m using the json2 script and started wondering what was happening in newer browsers when this script runs. Luckily I have the latest version and saw this line at the top:
So does this mean that if I include json2.js in my page then if native JSON is present it will use it otherwise it will use the json2.js ?
That’s correct. json2.js and the ECMA standard have identical APIs too, so parse and stringify work the same in both settings.
Yeah just been trying this out which is pretty cool.
So can I assume that if I include json2.js in my sites then I won’t have to do the checking for JSON in my jquery webservice call which you talk about in another post?
You wouldn’t need to test for its presence, but you would still need to use the dataFilter callback to force jQuery to use it. Until 1.3.3, jQuery won’t automatically use JSON.parse, even if it’s present.
Ah right ok. That’s not a problem really.
Cheers Dave
I find my browser has not support it now,may wait for a while.
btw:The most time,the server must keep the json returned sefely to be used.
I find it in http://www.json.com/json2.js
but I think I won’t use it if I must import one more js file,unless the browser help to do.
Safari 4.0.3 supports native JSON
Well presented! Thanks!
Any way to apply this sort of filter when using get() or getJSON()?
Thanks again!
Chas
If you set a dataFilter in $.ajaxSetup, it will apply to those shortcut methods. See this post for an example of doing that: http://encosia.com/2009/07/21/simplify-calling-asp-net-ajax-services-from-jquery/
Hi, I have seen a lot of demos using Json to call WebServices, but it’s safe? I mean if you can see the code behind, you easily can see where is the WebServices Located. There is any way to encript the WebServices URL?
Thanks
It is safe, as long as you secure any services that are sensitive. You can use .NET authorization on ASMX the same as you would on ASPX.
As long as you don’t trust the client too much, a user finding the service’s URL isn’t any more dangerous than them knowing the ASPX page’s URL.
For example, if you were building an AJAX shopping cart, you shouldn’t ever accept a price from the client-side. Instead, you should always accept a product ID and retrieve its price from a secure, server-side data store (probably a database). That way, even if the user does find the service URL and figure out how to manually POST to it, the “worst” they can do is add legitimate items to their cart at full price.