Space Cat, Prince Among Thieves

JSONP: Take It With a Grain of Salt

I don’t want anyone take this the wrong way. I love JSON. It is so much simpler to parse than XML, and is an all around exceptional way to represent data. I have one caveat though, and that is “JSON with Padding” or “JSONP” as it goes by.

Building this site I wanted to bring in images from my Flickr account as you may have noticed. Building the module in PHP, I basically ran file_get_contents on the feeds url and passed that directly into json_decode. It didn't work, the result was null. It had failed to decode. As a test I echoed the result of the file_get_contents to see what was up; it was succeeding at retrieving the feed. At a glance it looked like JSON, yet it was failing to parse. I knew something was up.

Here is an example result set:

  "title":"Uploads from donatj",
      "description":"<p><a href=\"\">donatj<\/a> posted a photo:<\/p> <p><a href=\"
photos/donatj/3581174864/\" title=\"STP81353\"><img src=\"\" width=\"180\" height=\"240\" alt=\"S
TP81353\" /><\/a><\/p> ",
      "author":" (donatj)",

On further examination I noticed, as you should have noted, the data is wrapped in a function. My first thought was that this violates the JSON Specification, so I immediately tweeted about how silly it was for Flickr to have an invalid JSON feed when their parent company Yahoo employs Douglas Crockford, the creator of JSON. I soon received a response from a colleague informing me that this was JSONP. He explained what it was, and how to use it in jQuery. I had not heard of JSONP.

It basically comes down to this: XMLHttpRequest will not, in order to protect against XSS, work across domains. Therefore, JSON cannot be directly retrieved nor parsed via JavaScript across domains.

This is where JSONP comes in. JSONP is essentially a regular JSON result set wrapped in a function. Rather than using XMLHttpRequest to retrieve the document, you dynamically attach a script tag to the page pointing the the JSONP document, which evokes a function call passing your JSON object to whatever function the JSONP is set to pass the data to, forgoing the need to eval anything.

I have a number of criticisms of this approach.

  • First and foremost, JSONP is at its very heart remote code execution. You must have absolute faith not only in the intentions of the site you are bringing the feed in from, but the security of said site as well, because the code is in fact being executed by the browser with no chance for putting regular expressions or other such safety mechanisms in place. This makes your site and visitors wide open to any and all malicious code a hacker may plant in the feed.
  • JSONP is a language specific data type. What I mean by this is that JSONP is designed for JavaScript, and even then strictly in the context of a web browser. There is no need, none, for JSONP anywhere else or in any other language (PHP, ASP.Net, Ruby on Rails). Making a feed in a language specific format is inherently in bad form.
  • Adding to the last point, other languages currently cannot naturally parse JSONP. As I ran into in PHP, it is not valid JSON and json_decode will not handle it. My colleagues answer was to write a regular expression to remove the function, but this is at best a hack.
  • Mixing function and data goes in the face of separation of concerns. You’ve got logic in your data, you’ve got data in your logic. Bad form, good sir, bad form.

JSONP is in many cases an unsafe practice, and more over its just evil. It is a necessary evil in some cases, but evil none the less.

There is at least one safe alternative to JSONP. The simplest solution provided you have access to server side code is to download, sanitize, optionally cache, and finally pass locally any remote JSON to the client rather than having the clients machine directly load the feed. Yes, this is added overhead on your side, bur for much added security.

If nothing else, it is up to you to weigh the risks and benefits before blindly using JSONP.

Comment by: Jon Henderson on

Jon Henderson's Gravatar I couldn't agree more. JSON is a data interchange format meaning that it's purpose is to exchange data in as neutral a way as possible. Given that JSON is native to JavaScript, it's purpose has in fact been augmented by being a data interchange format. JSONP sidesteps the beauty of JSON by eliminating it's neutrality. -5 neutrality, -2 usability.

Comment by: Michael on

Michael's Gravatar Pass nojsoncallback=1 to stop Flickr from being stupid.

Comment by: Jesse G. Donat on

Jesse G. Donat's Gravatar @Michael

Thank you. I have since figured this out, but have yet to update the post.

Comment by: mr guy on

mr guy's Gravatar Yeah now I can agree with you about the shortcomings of JSONP, but it's existence isn't really a design choice so much as a need.Due to cross origin ajax security issues, JSONP arose to circumvent browser safeguards. So it stands to reason it only exists in the browser ecosystem.

Similarly I can agree with you that having tools only in the browser ecosystem is not ideal.. but thats.. too bad. The browser ecosystem is hugely different than other niche areas with thousands of changing daily use cases and billions of users.

To call removing the function string before decoding a hack seems too motivated by rage against the format lol. The "padding" in JSONP is just wrapping JSON in a function. Performing the reverse operation is a high-fidelity method of conversion. Nothing wrong with simple.

Email address will never be publicly visible.

See my Tweet about comment formatting.