Jump to content

JSONP

From Wikipedia, the free encyclopedia

This is an old revision of this page, as edited by Derekleungtszhei (talk | contribs) at 04:00, 1 January 2015. The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

JSONP or "JSON with padding" is a communication technique used in JavaScript programs running in web browsers to request data from a server in a different domain, something prohibited by typical web browsers because of the same-origin policy. JSONP takes advantage of the fact that browsers do not enforce the same-origin policy on <script> tags.

Note that for JSONP to work, a server must know how to reply with JSONP-formatted results. JSONP does not work with JSON-formatted results. The JSONP parameters passed as arguments to a script are defined by the server. A typical JSONP request is similar to the following sample code:

<!-- Request sent via a script tag -->
<script src="https://status.github.com/api/status.json?callback=apiStatus"></script>
<!-- Data received as an execution of the predefined function. -->
<script> function apiStatus(data) { console.log(data.status); } </script>

How it works

To see how this technique works, first consider a URL request that returns JSON data. A JavaScript program might request this URL via XMLHttpRequest, for example. Suppose the user ID of a person Foo is 1234. A browser requesting the URL http://server2.example.com/Users/1234, passing the ID of 1234, would receive something like:

{
    "Name": "Foo",
    "Id": 1234,
    "Rank": 7
}

This JSON data could be dynamically generated, according to the query parameters passed in the URL.

Here, a HTML <script> element specifies for its src attribute a URL that returns JSON:

<script type="application/javascript"
        src="http://server2.example.com/Users/1234">
</script>

The browser will, in order, download the script file, evaluate its contents, interpret the raw JSON data as a block, and throw a syntax error. Even if the data were interpreted as a JavaScript object literal, it could not be accessed by JavaScript running in the browser, since without a variable assignment object literals are inaccessible.

In the JSONP usage pattern, the URL request pointed to by the <script>'s src attribute returns JSON data, with a function call wrapped around it. In this way, a function that's already defined in the JavaScript environment can manipulate the JSON data. A JSONP payload might look like this:

functionCall({"Name": "Foo", "Id": 1234, "Rank": 7});

The function call is the "P" of JSONP—the "padding" around the pure JSON, or according to some[1] the "prefix". By convention, the browser provides the name of the callback function as a named query parameter value, typically using the name jsonp or callback as the named query parameter field name, in its request to the server, e.g.,

<script type="application/javascript"
        src="http://server2.example.com/Users/1234?jsonp=parseResponse">
</script>

In this example, the received payload would be:

parseResponse({"Name": "Foo", "Id": 1234, "Rank": 7});

Padding

While the padding (prefix) is typically the name of a callback function that is defined within the execution context of the browser, it may also be a variable assignment, an if statement, or any other JavaScript statement. The response to a JSONP request is not JSON and is not parsed as JSON; the returned payload can be any arbitrary JavaScript expression, and it does not need to include any JSON at all. But conventionally, it is a JavaScript fragment that invokes a function call on some JSON-formatted data.

Said differently, the typical use of JSONP provides cross-domain access to an existing JSON API, by wrapping a JSON payload in a function call.

Script element injection

JSONP makes sense only when used with a script element. For each new JSONP request, the browser must add a new <script> element, or reuse an existing one. The former option—adding a new script element—is done via dynamic DOM manipulation, and is known as script element injection. The <script> element is injected into the HTML DOM, with the URL of the desired JSONP endpoint set as the "src" attribute. This dynamic script element injection is usually done by a JavaScript helper library. jQuery and other frameworks have JSONP helper functions; there are also standalone options.[2][3][4]

An example of the dynamically injected script element for a JSONP call looks like this:

<script type="application/javascript"
        src="http://server2.example.com/Users/1234?jsonp=parseResponse">
</script>

After the element is injected, the browser evaluates the element, and performs an HTTP GET on the src URL, retrieving the content. Then the browser evaluates the return payload as JavaScript. This is typically a function invocation.

In that way, the use of JSONP can be said to allow browser pages to work around the same-origin policy via script element injection.

The script runs within the scope of the including page and, as such, is still subject to cross-domain restrictions relative to the including page's domain. This means that one cannot, for example, load a library hosted on another site via JSONP and then make XMLHttpRequest requests to that site (unless cross-origin resource sharing (CORS) is supported) although one could use such a library to make XMLHttpRequests to one's own site.

Cross-domain requests using a proxy server

The JavaScript same-origin policy normally prevents browsers from sending AJAX requests to a different domain and receiving a response (newer browsers that support CORS can relax this constraint). A cooperating proxy server, however, does not have such restrictions and can relay a browser request to a server in a separate domain, store the result, and then return that JSON payload when the browser makes a second request. The server would be instructed within the first request to store the output (POST returning JSON payload) temporarily into a local store (for example memcached or within a session variable), and a second request from the browser then would fetch the cached response to the initial query.[5] The xd_arbiter.php used by Facebook's JS SDK is a popular example of this cooperating server technique.[6]

Security concerns

Including script tags from remote servers allows the remote servers to inject any content into a website. If the remote servers have vulnerabilities that allow JavaScript injection, the page served from the original server is exposed to an increased risk. If an attacker can inject any JavaScript into the original web page, then that code can retrieve additional JavaScript from any domain, bypassing Same-origin policy.[7] The Content Security Policy HTTP Header lets web sites tell web browsers which domain's scripts should be included from.

An effort is underway to define a safer strict subset definition for JSON-P[8] that browsers would be able to enforce on script requests with a specific MIME type such as "application/json-p". If the response didn't parse as strict JSON-P, the browser could throw an error or just ignore the entire response. For the moment, however, the correct MIME type is "application/javascript" for JSONP.[9]

Cross-site request forgery

Naive deployments of JSONP are subject to cross-site request forgery (CSRF or XSRF) attacks.[10] Because the HTML <script> tag does not respect the same-origin policy in web browser implementations, a malicious page can request and obtain JSON data belonging to another site. This will allow the JSON-encoded data to be evaluated in the context of the malicious page, possibly divulging passwords or other sensitive data if the user is currently logged into the other site.

This is problematic only if the JSON-encoded data contains sensitive information which should not be disclosed to a third party, and the server depends on the browser's same-origin policy to block the delivery of the data in the case of an unauthorized request. This security dependency on the browser's same-origin policy can be avoided by the server determining if the request is authorized and only putting the data on the wire if it is. Exclusive use of cookies for determining if a request is authorized should be avoided as it is subject to cross-site request forgery.

Rosetta Flash

Rosetta Flash is an exploitation technique that allows an attacker to exploit servers with a vulnerable JSONP endpoint by causing Adobe Flash Player to believe that an attacker-specified Flash applet originated on the vulnerable server. Flash Player implements same-origin policy allowing to make requests (with cookies) and receive responses from the hosting site. The applet can then send the retrieved data back to the attacker. This is a cross-origin exploit with an impact similar to embedding an arbitrary Flash applet in the vulnerable domain. The exploit uses an ActionScript payload compiled to an SWF file composed entirely of alphanumeric characters by crafting a zlib stream with a particular header and DEFLATE blocks with ad-hoc Huffman coding. The resulting alphanumeric-only SWF file is then used as the callback parameter of a JSONP call. High profile sites such as Google, YouTube, Twitter, Yahoo!, Yandex, LinkedIn, eBay, Instagram and Tumblr were all vulnerable until July 2014.[11] This vulnerability was discovered and published by Google security engineer Michele Spagnuolo[12] and has CVE 2014-4671[13] and CVE 2014-5333.[14] Adobe Flash Player release version 14.0.0.145, released on July 8, 2014, introduced stronger validation of Flash files,[15] and in version 14.0.0.176, released on August 12, 2014, finalized the fix,[16] preventing this exploit from working.

History

In July 2005 George Jempty suggested an optional variable assignment be prepended to JSON.[17][18] The original proposal for JSONP, where the padding is a callback function, appears to have been made by Bob Ippolito in December 2005[19] and is now used by many Web 2.0 applications such as Dojo Toolkit, Google Web Toolkit and Web services.

An unnamed process equivalent to JSONP has been used by PostX envelopes (now owned by Cisco Systems and deployed on Cisco's Email Security Appliance and Cisco Registered Envelope Service (CRES)) since May 2002.[citation needed]

See also

References

  1. ^ "Experimental RDF result set to JSON translator". Retrieved February 20, 2012.
  2. ^ "example jsonp library on pastebin".
  3. ^ "Basic JSONP helper (pure JS)".
  4. ^ "jQuery's $.getJSON utility".
  5. ^ http://www.flinkwise.com/technology-blog/a-way-to-send-json-p-post-requests-to-another-domain-with-jquery-and-rails-in-the-back-end/
  6. ^ Kinsey, Sean. "Facebook and Cross domain messaging clarification?". Stack Exchange, Inc. Retrieved 22 November 2013.
  7. ^ Ben Hayak (2014-10-17). "Same Origin Method Execution" (PDF). Retrieved 2014-10-22.
  8. ^ "Safer cross-domain Ajax with JSON-P/JSONP". JSON-P.org. Retrieved 30 October 2011.
  9. ^ Grey, Eli (2010-06-27). "Is this safe for providing JSONP?". stackoverflow.com. Retrieved 2012-09-07.
  10. ^ Grossman, Jeremiah (January 27, 2006). "Advanced Web Attack Techniques using GMail". Retrieved July 3, 2009.
  11. ^ Michele, Spagnuolo. "Abusing JSONP with Rosetta Flash". Retrieved 20 July 2014.
  12. ^ "Google - list of software vulnerabilities discovered or fixed by Googlers". Retrieved July 29, 2014.
  13. ^ "MITRE: CVE-2014-4671". Retrieved July 29, 2014.
  14. ^ "MITRE: CVE-2014-5333". Retrieved August 21, 2014.
  15. ^ "Adobe Security Bulletin APSB14-17". Retrieved July 29, 2014.
  16. ^ "Adobe Security Bulletin APSB14-18". Retrieved August 21, 2014.
  17. ^ "eval'ing JSON". July 19, 2005.
  18. ^ "json: Message: Re: Comments". August 17, 2005.
  19. ^ "Remote JSON - JSONP". from __future__ import *. Bob.pythonmac.org. December 5, 2005. Retrieved September 8, 2008.