Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is getJSON() safe to call on untrusted URL?

Is it safe to call jQuery's $.getJSON() with a URL argument that came from an untrusted source, such as another user? In other words, is it safe to call $.getJSON() with an untrusted URL? I will be careful not to trust the response and to handle the response safely, but does the call itself pose a security risk?

In other words, I'm talking about something like:

$.getJSON(url_from_user, function(...) { ... handle response safely ...});

or

$.getJSON('http://evil.com/foo.json', function(...) {...});

Could this allow code injection or XSS if some untrusted user provides a malicious value for url_from_user or if someone malicious controls the evil.com site? Again, assume that any JSON object returned will be treated safely.


More details and research I've done

The documentation for getJSON doesn't say anything either way about whether this scenario is secure. Logically, I would expect this scenario to be safe, as I would expect jQuery's implementation to download the text of the JSON object via XHR, parse this text using a safe JSON parser, and then return the JSON object.

However, after looking at the jQuery source code, I have some doubts about whether this is safe. Browsing through the source code for jQuery, it looks like this scenario might potentially allow XSS. The code for getJSON() is a bit elaborate (see src/ajax.js), but it seems to select a "transport" and then use it to send the AJAX request. I see that src/ajax/script.js registers a transport called the "script tag hack transport". This transport works roughly as follows: it adds a script tag to the document, e.g., <script src="http://evil.com/foo.json">, and registers an onload handler that runs when the downloaded script has executed. In other words, the "script tag hack transport" is fundamentally insecure if the site is controlled by an attacker: it is including attacker-controlled script into the document and executing it. Besides the script tag hack transport, there's also a XHR transport that uses the browser's XMLHttpRequest() API. I am having a hard time following the twisty logic that determines under which conditions the "script tag hack" transport will be used.

So, coming back to my original question, is it safe to call $.getJSON() with a user-provided URL? If it is potentially unsafe under some conditions, under what conditions (e.g., browser versions) is it safe/unsafe?

like image 328
D.W. Avatar asked Mar 13 '15 00:03

D.W.


1 Answers

Unless you configure your request to NEVER use JSONP (which jQuery will automatically try to use for some cross origin requests in some circumstances), it is not safe to use $.getJSON() against any random foreign URL.

If jQuery switches to JSONP, that would directly enable script injection into your page from the other origin since JSONP works precisely by script injection (in order to circumvent same-origin limitations with regular Ajax calls).

To prevent this type of mis-use, you will have to prevent any use of JSONP and would have to investigate the surest way to do that in jQuery. You could perhaps switch to $.ajax() where you can specify a lot more options to control things.

If this were my code, I might be tempted to even skip jQuery entirely for this one Ajax call and just use my own xmlHttpRequest object to absolutely guarantee that it was only doing a pure Ajax call (no fallback to any other transport like JSONP).

Update:

I've been trying to find a circumstance where $.getJSON() will issue a JSONP request in various test scenarios on a jsFiddle. I have not been able to find one. Either the target site has an Access-Control-Allow-Origin header that allows cross origin requests in which case jQuery just does a cross origin Ajax call or it doesn't have the header and jQuery just fails the getJSON() call. So, it looks like it would take some serious study of a specific version of jQuery to figure out if it could actually be tricked into doing a JSONP call in some sort of "auto" mode when you didn't explicitly ask for one.

Update 2: Found an actual vulnerability

I found a vulnerability. If the URL sent to $.getJSON() contains a query parameter callback=, then jQuery will execute JSONP and the target host can inject whatever script it wants with the response.

Here's a demo using a publicly accessible Flickr JSONP endpoint:

http://jsfiddle.net/jfriend00/z6ah9eh2/

This doesn't doing anything with mal-intentions, but it does execute arbitrary Javascript that is up to the target site via $.getJSON(). So, it is definitely vulnerable to code injection via JSONP.

Here's a quote from the jQuery docs for $.getJSON():

If the URL includes the string "callback=?" (or similar, as defined by the server-side API), the request is treated as JSONP instead.

And, "treated as JSONP" means it's going to insert a script tag and request and run a script from the site in the URL - thus opening a cross site scripting vulnerability if you access an untrusted site with JSONP.


One of the ideas behind JSON is that it can be parsed with a plain text parser that strictly adheres to the JSON specification and NOTHING besides pure JSON is allowed or can get through. If anyone tries to sneak some Javascript code into a JSON string, any semi-decent JSON parser will just reject the JSON as invalid and throw an exception. In a proper world (which $.getJSON() is), JSON is not parsed with the Javascript parser, it is parsed with it's own text parser that strictly accepts only valid JSON, not other Javascript constructs.

That is the idea behind a safe and secure implementation of a JSON parser which it is believed that $.getJSON() uses (there could always be unknown bugs in any parser, but work has been done to design it to be safe).

So, this hurdle has been passed. There are no tricks that can be inserted into a piece of JSON that is parsed with a decent JSON parser that will cause backdoor code injection.


Now, another hurdle depends upon what you are doing with the JSON itself and whether your handling or use of the JSON enables potential mal-behavior or not.

For example, if you pull a string property from the JSON and execute it as a method on an object without any checking to see if that string is an expected value, then your code might be able to be tricked into executing a method that you did not intend. This still doesn't insert code into your page, but it does execute something you didn't intend. You can avoid that by proper validation of the data before you use it. So, if as you say, you are using the JSON safely, then this should not be an issue.

like image 137
jfriend00 Avatar answered Dec 04 '22 00:12

jfriend00