I am writing an app right now that uses jQuery and JSONP to get JSON from 3rd party servers. The main idea behind my app is that it is a Front End with only GUI logic and 3rd party servers can be written by anyone to use the Front End.
I have no idea what security issues could arise from this but I definitely see it as a potential issue. What are some steps I can take to make sure that a 3rd party server doesn't completely crash my site that will be running the GUI?
JSONP means that you execute third-party javascript which should return a Javascript object. The script you load with JSONP can do anything a local script could, thus it is an XSS attack vector in two ways: either if the third party you request the JSONP data from is evil, or if the data is changed with a man-in-the-middle attack.
The second type of attack can be avoided by only doing JSONP over secure connections (or can be disregarded if your own page is sent over an insecure connection, in which case there are easier ways to do a man-in-the-middle attack); the first type is inherent to JSONP and cannot be avoided. You should only use JSONP when you trust the source. Otherwise, you can either set up an AJAX gateway on your own server and request JSON data through that (this will only work if the JSONP service does not require authentication), or use cross-domain AJAX requests (which do not work in older browsers, and require certain permissions from the JSONP server).
If the third-parties aren't trustworthy, you have a large problem here. Instead of sending JSONP code, they could send any JavaScript they want, potentially damaging your site or stealing users' information.
JSONP works by just including the remote data on your page with <script> tags. It is designed to avoid the browser's security restrictions, and so should only be used with trustworthy sources.
A client-side only solution to this problem does not exist.
EDIT: Oh, I misread your question. I thought the client was going to be receiving the JSON.
JSONP is just a JSON object wrapped in a javascript function call. Normally if you were operating from a server you would just request the unwrapped JSON object itself, but even with the JSONP object it's difficult to hurt yourself unless you are running eval() on it.
Are you using an existing JSON library? If so, you should be fine.
Are you parsing it yourself? If so, avoid eval and you should be fine.
Well, JSON describes an object, not an executable function. What JSONP is doing is rendering that result of a GET request as a function on your client and executing it. This would suggest that the biggest security concern you would consider is what your code is doing with the data.
Related
I'm working on the project where the client has the back-end code in ServerA, and my front-end code, which is supposed to talk to back-end via AJAX requests is on ServerB, and they are in different domains. Because of the same origin policy, I'm not able to make those requests successfully (neither POST nor GET). Is it possible to enable it somehow without changing the back-end code to handle the JSONP? eg., white list that particular domain, or something?
I tried to emulate this in my local network where the back-end code is running on 10.0.1.4 (different machine), and I'm accessing it from localhost (apache), but couldn't figure out anything that doesn't require using jsonp. When calls are made, I'm not even seeing anything in the logs in the back-end, but it works fine from the REST client and by just loading the URL for GET requests. How are public API requests implemented that are not using JSONP?
I need at least one method (POST or GET) to work. Thanks.
Is it possible to enable it somehow without changing the back-end code
to handle the JSONP? eg., white list that particular domain, or
something?
Yes, you could write a server side script on your domain that will serve as a bridge between your and the remote domain and then send an AJAX request to your script.
Don't expect miracles. If you don't have control over the remote domain you are busted. The same origin policy restriction that's built into browsers for security reasons busts you. Well, you could always write your own browser that doesn't implement this policy, but I think you get my point.
Common workarounds include JSONP and CORS but they involve control over the remote domain. If you don't have control then read the my previous sentence as well as my first sentence.
Here's a nice guide I invite you consulting that covers some common techniques allowing to achieve cross domain AJAX with jQuery. Then adapt the one that fits best your scenario. And there's always the heavy artillery solution that involves bridging the 2 domains with a server side script which works bullet-proof in 100% of the cases if none of the other workarounds help you.
Is it possible to enable it somehow without changing the back-end code to handle the JSONP? eg., white list that particular domain, or something?
Hmmm, mostly no. You must allow JSONP or "white list" things via CORS (which is very easy to do). Or you can use YQL as a cross-domain proxy.
Three solutions posted here:
http://devlog.info/2010/03/10/cross-domain-ajax/
I've tried the third option since it just worked for me.. and I didn't have to go through any extra stress as it just handled things just like a regular ajax call.
Updating answer as this was posted 2 years ago:
LINK ABOVE NO LONGER WORKS.
Server side proxy:
the old page also talks about using a server side proxy, which means your server makes a call to another server, grabs all the data and sends it off to a page resting on that server. There is no problem for one server to fetch data from another server. So then your page can make a regular ajax call to that server. I didn't go with this option as it required more manual labor. So I'd suggest going with the option detailed here:
JSONP with jQuery
Make sure the provider supports JSONP.
Set the dataType option to jsonp, and if the provider uses a different GET param other than 'callback', specify the jsonp option to that parameter name.
$.ajax({
// ... Use the AJAX utility as you normally would
dataType: 'jsonp',
// ...
});
jQuery will generate a unique callback name for this request (something like json1268267816). Thus, the reply from a web service would be something like:
json1268267816({'uid': 23, 'username': 'Chroder', 'name': 'Christopher Nadeau'});
But jQuery handles it all seamlessly, so you as the developer just handle it like a normal AJAX request using the same jQuery success/failure/complete callback hooks.
Drawbacks:
The first limitation to this method is that you have to rely on the provider to implement JSONP. The provider needs to actually support JSONP -- they need to wrap their JSON data with that callback function name.
Then the next limitation -- and this is a big one -- is that JSONP doesn't support POST requests. Since all data is passed in the query string as GET data, you are severely limited if your services require the passing of long data (for example, forum posts or comments or articles). But for the majority of consumer services that fetch more data than they push, this isn't such a big problem.
However,
Using a library like jQuery that supports JSONP, these details of inserting the special script tag and creating the special callback function are all taken care of automatically. Using a JS library, usually the only difference between JSONP and real AJAX is that you enable a 'jsonp' option.
I don't see how the callback function in JSONP is any different from the success callback function in AJAX.
Given #1, I don't see how it is fundamentally more secure.
So is the only difference an artificial same-domain constraint with AJAX?
Why can't AJAX just allow cross-domain requests; if this can cause a security hole, wouldn't the attack just XSS a JSONP request?
Confused,
Max
An ajax call is an actual HTTP request from your client directly to a server. Ajax calls can be synchronous (blocking until they complete) or asynchronous. Because of same-origin security protections, ajax calls can only be made to the same server that the web page came from unless the target server explicitly allows a cross origin request using CORS.
JSONP calls are an interesting hack with the <script> tag that allows cross-origin communication. In a JSONP call, the client creates a script tag and puts a URL on it with an callback=xxxx query parameter on it. That script request (via the script tag insertion) is sent by the browser to the foreign server. The browser just thinks it's requesting some javascript code. The server then creates some special javascript for the purposes of this call and in that javascript that will get executed by the browser when it's returned, the server puts a function call to the function named in the callback=xxxx query parameter. By either defining variables of by passing data to that function, the server can communicate data back to the client. For JSONP, both client and server must cooperate on how the JSONP call works and how the data is defined. A client cannot make a JSONP call to a server that doesn't explicitly support JSONP because the exact right type of JSONP response has to be built by the server or it won't work.
So, the two communication methods work completely differently. Only ajax calls can be synchronous. By the nature of the <script> tag insertion, JSONP calls are always asynchronous.
In an Ajax call, the response comes back in a ajax event handler.
In a JSONP call, the response comes when the returned Javascript calls a function of yours.
In some ways, JSONP is a security hole that bypasses the cross-origin security mechanism. But, you can only call servers that explicitly choose to support a JSONP-like mechanism so if a server doesn't want you to be able to call it cross-origin, it can prevent it by not supporting JSONP. You can't make regular ajax calls to these other servers.
The browser makers can't really close this loophole because if they did zillions of web pages would break that either already use JSONP or load scripts from other domains. For example, every page on the web that uses jQuery off the Google or Microsoft CDNs would break because the browser wouldn't be allowed to download javascript from cross-origin domains.
JSONP was largely invented as a work-around to be able to make cross-origin requests. But, since JSONP requires explicit server support in order to work, it wasn't really a security problem because a JSONP call can only be made to a server that explicitly decided to allow that type of cross origin call. JSONP is used much less now than it used to be because CORS was invented as a more elegant way to control/allow this. CORS stands for Cross Origin Resource Sharing and it provides a means for a target server to tell a web browser exactly what type of cross origin requests are allowed and even to tell it which web page domains are allowed to make such requests. It is has much finer control available than JSONP and all modern browsers now support CORS.
Here's an example of how a cross-origin call causes problems. If you could load any arbitrary web page from any other web page or make any arbitrary ajax call, then imagine you were already logged into your webmail interface on Yahoo in so some other browser window. This means that your cookies are set to allow requests from your browser to fetch data from Yahoo. If the javascript in some other web page was allowed to make a webmail request to Yahoo (that would automatically have your cookies attached), it could then fetch all your webmail data and send it back to it's own site. One web site could rip off all the logged-in data from any other web site. All web security would be broken.
But, the way we have it today, as long as Yahoo doesn't support a JSONP interface that uses those same web cookies, it is safe from unauthorized JSONP requests.
Here are some other good writeups on the dangers of cross-origin ajax and why it has to be prevented:
Why the cross-domain Ajax is a security concern?
Why Cross-Domain AJAX call is not allowed?
Why are cross-domain AJAX requests labelled as a "security risk"?
JSONP's callback is not an actual callback. Rather, JSONP works by script injection. E.g., if you want to make a JSONP call, you insert this script element into the DOM:
<script src="http://example.com/ajaxendpoint?jsonp=parseResponse"></script>
The server's response will be something like this:
parseResponse({"json":"value"});
It will be evaluated in the window's global scope. So essentially JSONP is like a remote exec(), where the server is advised what string to create to execute.
This is very different from Ajax: with JSONP, the response is evaluated in the script's global scope; with XMLHttpRequest, the response is received as a string and not evaluated.
(Also, JSONP can only be used with GET, whereas AJAX allows any http method.)
Thus to your second issue, "I don't see how it is fundamentally more secure." Well, you are right, JSONP is actually extremely insecure. The server can return any script it wants, and do anything it wants to your browser!
Cross-domain requests are insecure because they can be used to reveal information about the current page to a page on another domain.
And you are right that any XSS attack can just use JSONP. The purpose of CORS is not to prevent XSS (if you have untrusted scripts running on your page you are hosed anyway).
The fundamental difference is that, for some reason, it's perfectly fine to load javascript files located on other domains (via script tag), but it is not OK by default to load other cross domain resources.
I'm with you, in that the delineation seems rather arbitrary. In jQuery, when you do a JSONP call, effectively you are creating a script tag, loading the resource, and then the jQuery library executes your script by calling the function defined in that JSONP result.
In my eyes, I cannot think of an additional vector of attack introduced by allowing cross domain AJAX which is not already gaping wide by allowing cross domain script loading, which is a common practice used everywhere (jQuery by googleCDN, advertising scripts, google analytics, and countless others).
From wikipedia
In addition, many legacy cross-domain operations predating JavaScript are not subjected to same-origin checks; one such example is the ability to include scripts across domains, or submit POST forms.
I am aware if you try to scrape the google/yahoo finance websites you're at risk of being blocked by their server. I was therefore wondering what if you could spoof the google/yahoo ajax call (which they use to update the prices on the webpage if you leave it open) back to the server each time you wanted a price, surely the google/yahoo server wouldnt count this towards the daily request limit?
Is this possible?
If you try to do it via JavaScript, you'll probably run into problems with the same origin policy. You can't do ajax requests to Google/Yahoo from one of your own sites (when not using an official JavaScript API provided by Google/Yahoo).
You can try it using another programming language by inspecting the http calls using Wireshark, Fiddler or similar, and rebuilding the request with the correct headers. This will probably violate the terms of service though (getting you banned), and might even be illegal.
I need to find a way to notify a 3rd party website about an user action on my website. A server sided connection is not desired. Hashing with private keys is used to sign the request so users can't abuse it.
My question is how I can send this request safely.
tracking image: XSA possible
iframe: XSA, frame breaker
script include: evilness at its best
JSONP (with jQuery): ??
others?
Does someone know if it's possible to inject Javascript in JSONP answers? I mean to bypass browser boundaries JSONP is Javascript that calls a function with the JSON as parameter but it could also contain other javascript calls. Does jQuery somehow check if there is malicious content in jsonp callbacks?
If you only need to target modern browsers, and you control all the domains, you can create an HTTP access control policy to allow them to communicate with each other. However, since that doesn't appear to be the case, you're going to be stuck with JSONP.
It's funny that you mention "script include" as "evilness at its best", because that's exactly what JSONP is. Since, until recently, browsers were incapable of cross-domain requests, the only way to get anything from a 3rd-party client-side was to include a script from that 3rd party. JSONP simply takes advantage of this workaround returning the JSON inside of a function definition, which your script can then call to get the included data.
Is it possible to do a cross-site call, in Javascript, to a WCF service?
I don't mind if it's a POST or a GET.
But I've heard that these days, browsers don't allow cross-site calls with either POST or GET.
How can I circumvent this and still call a WCF Service?
There's not a whole lot you can do to circumvent the browser's cross-site scripting blockers. Those blockers stop XMLHTTPRequest's from happening to any domain but the one that loaded the containing script or page.
That said, there is one commonly used workaround: Use JavaScript to write a new entry into the DOM that references a src that is a cross-site URL. You'll pass all your RPC method arguments to this "script" which will return some JavaScript that will be executed, telling you success or failure.
There's no way to do a POST in this manner, the src URL must be a GET, so you can pass arguments that way. I'm not sure if WCF has a "GET only" method of access. And, since the browser will expect the result of the remote tag to be a valid JavaScript object, you'll have to make sure that your WCF service obeys that as well, otherwise you'll get JavaScript errors.
Another common method of circumventing cross-site scripting is to write a proxy for your requests. In other words, if you want to access domain test.com from scripts hosted on example.com, then make some URL on example.com that proxies the request over to test.com in the proper way.
For your example, the proxying is likely the right answer, assuming that WCF doesn't have it's own cross-site scripting restrictions.
Are you using jQuery by any chance? jQuery supports Cross-Domain JSON requests using "JSONP". You will be limited to GET requests, but I've tried it out and it works well! It's also very simple to get working.
See the "Cross-Domain getJSON (using JSONP) " section on this page for details:
http://docs.jquery.com/Release:jQuery_1.2/Ajax
And here's some background on JSONP:
http://bob.pythonmac.org/archives/2005/12/05/remote-json-jsonp/
Let me know how it goes!
New W3C recommendations are being standardised to allow cross-site requests between trusted parties via the Access Control for Cross-Site Requests specification.
This requires a server serving suitable Access Control HTTP headers and a browser capable of understanding and acting upon such headers.
In short, if a remote host says it likes your domain, and a browser understands what this means, you can perform xmlHttpRequests against that host regardless of the same origin policy.
Currently very few browsers support this functionality. IE8 apparently does (I haven't tested it) and Firefox 3.1 does (I have tested this extensively). I expect other browsers to follow suit quite quickly.
You shouldn't expect sufficient adoption of compatible browsers until 2012 at the earliest.
That's the ultimate solution to the problem. The downside is waiting a few years before it can be used in mainstream applications.
If this is for use within an environment you fully control, such as for an intranet where you can determine which browser is used and where you can configure multiple servers to issue the correct headers, it works perfectly.
To expand on Ben's answer... I extended our WCF service to support JSONP calls from jQuery using code similar to this example from Microsoft:
http://msdn.microsoft.com/en-us/library/cc716898.aspx