Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to make a secure JSONP request?

I only have to support new browsers.

I have to rely on an external service to provide JSONP data, I do not own that service and it does not allow CORS.

I feel very uneasy having to trust JSONP requests from the external server, since they can run arbitrary code on my end, which would allow them to track my users, and even steal their information.

I was wondering if there was any way to create a JSONP request that is also secure?

(Related: How to reliably secure public JSONP requests? but not with the new browser relaxation)

NOTE: I asked/answered it Q&A style, but I'm very open to other ideas.

like image 554
Benjamin Gruenbaum Avatar asked May 21 '13 00:05

Benjamin Gruenbaum


People also ask

Is JSONP insecure?

JSONP is vulnerable to the data source replacing the innocuous function call with malicious code, which is why it has been superseded by cross-origin resource sharing (available since 2009) in modern applications.

Does JSONP still work?

JSONP is still useful for older browser support, but given the security implications, unless you have no choice CORS is the better choice.

How does JSONP request work?

It works by dynamically adding a <script> tag to the DOM and calling a predefined function with the remote web service's JSON data as the parameter. The <script> tag is not subject to the same origin policy and therefore can request content cross-domain.

What does JSONP use for request?

JSONP stands for JSON with Padding. Requesting a file from another domain can cause problems, due to cross-domain policy. Requesting an external script from another domain does not have this problem. JSONP uses this advantage, and request files using the script tag instead of the XMLHttpRequest object.


1 Answers

Yes!

It is possible. One way to do it would be to use WebWorkers. Code running in WebWorkers has no access to the DOM or other JavaScript code your page is running.

You can create a WebWorker and execute the JSONP request with it, then terminate it when you're done.

The process is something like this:

  • Create a WebWorker from a blob with the URL to request

  • Use importScripts to load the JSONP request with a local callback

  • When that callback executes, post a message back to the script, which in turn will execute the actual callback message with the data.

That way, an attacker would have no information about the DOM.

Here is a sample implementation:

//   Creates a secure JSONP request using web workers.
//   url - the url to send the request to
//   data - the url parameters to send via querystring
//   callback - a function to execute when done
function jsonp(url, data, callback) {
    //support two parameters
    if (typeof callback === "undefined") {
        callback = data;
        data = {};
    }
    var getParams = ""; // serialize the GET parameters
    for (var i in data) {
        getParams += "&" + i + "=" + data[i];
    }
    //Create a new web worker, the worker posts a message back when the JSONP is done
    var blob = new Blob([
        "var cb=function(val){postMessage(val)};" +
        "importScripts('" + url + "?callback=cb" + getParams + "');"],{ type: "text/javascript" });
    var blobURL = window.URL.createObjectURL(blob);
    var worker = new Worker(blobURL);

    // When you get a message, execute the callback and stop the WebWorker
    worker.onmessage = function (e) {
        callback(e.data);
        worker.terminate();
        };
    worker.postMessage(getParams); // Send the request
    setTimeout(function(){
        worker.terminate();//terminate after 10 seconds in any case.
    },10000);
};

Here is sample usage that works in JSFiddle:

jsonp("http://jsfiddle.net/echo/jsonp", {
    "hello": "world"
}, function (response) {
    alert(response.hello);
});

This implementation does not deal with some other issues but it prevents all access to the DOM or the current JavaScript on the page, one can create a safe WebWorker environment.

This should work on IE10+, Chrome, Firefox and Safari as well as mobile browsers.

like image 81
Benjamin Gruenbaum Avatar answered Oct 19 '22 12:10

Benjamin Gruenbaum