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.
Related
JSONP is said to "by-pass" the same origin policy. I take this to mean that using it allows the script to load from a remote server on a different domain and run locally on a website.
I'm not clear however on what exactly can be done by the script while it is running.
Is it just as privileged at JavaScript loaded from the same domain? Are there any additional restrictions imposed on JSONP that one can count on?
In a browser, <script> tags may reference scripts located in any domain. Script resources are not subject to the same-origin restrictions that an Ajax request is.
As such, you can dynamically insert a script tag that will refer to a script on any domain and it will load successfully and not be blocked by same origin restrictions.
This is how JSONP works - by making a cross origin request by requesting a remote script to load and run. It is not a blanket bypass of the same origin restrictions because you cannot just directly make a remote API call using JSONP as the server you are contacting must explicitly support JSONP because it's a completely different type of response. So, in essence, the server you are contacting must explicitly support and allow this cross origin request via JSONP.
I'm not clear however on what exactly can be done by the script while
it is running.
Once you request a JSONP script, that script is just a piece of Javascript running in your page. It can literally do anything that any script running in your page can do.
Is it just as privileged at JavaScript loaded from the same domain?
Are there any additional restrictions imposed on JSONP that one can
count on?
It's just a script running in your page. It can do anything that any script running in your page can do. By convention, it is supposed to call a callback function that was specified in the URL and pass it some data (the result of the request), but it could do any other thing that Javascript in your page can do.
There are no additional restrictions on JSONP scripts. The browser doesn't know if a script is JSONP script or not. It's just a script that can do exactly the same things as any other script.
JSONP is basically a hack that solved a problem before browsers supported CORS. I can't think of any reason these days to design a solution based on JSONP any more if you can use CORS. CORS is more secure as it doesn't let some other site run random Javascript in the context of your page.
JSONP works by employing ordinary <script> tags and content fetched as JavaScript via an HTTP GET. The browser basically thinks it's just fetching another script for use by the page, so the code with which the third-party site responds can do anything it wants to.
"Well-behaved" JSONP sources send back, by convention, a call to the function whose name you give as the "callback" parameter in the URL. That is, the server responds with a JavaScript statement:
yourCallback({ name: value, ... });
There's really no way for your code on the page to tell whether that's really all that happened, however.
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.
Is it possible to do AJAX calls from inside an iframe that has a different domain source?
I've tried script injection but it doesn't work because the iframe's source is secure.
I made a simple fiddle with California DMV website here.
I'm getting DOM exception 8 error. Is it a security issue?
It is not possible to modify or make JS calls in an iframe with a different domain source. This is restricted in all browsers for security reasons.
See the "Same Origin Policy" for a description of how inter frame security works. In a nutshell, there is very little communication allowed between frames on a different domain for security reasons. You cannot make any direct Javascript calls between frames on different domains.
There is a way to make cross domain ajax calls and it involves using JSONP. Basically, you inject a script tag into your own frame and that script tag points to server endpoint anywhere on the web. Since the src value of a script tag is not restricted by the same origin policy, you can reach that server. But, now you need to have a way to get that result back. That is done using JSONP where you specify in your server request a javascript function that you want the returned javascript to call. That returned javascript can have javascript data in it that is then passed to the desired function. JSONP requires cooperation between both client code and the server code since a normal ajax call might not support the extra part of JSONP. But, with this cooperation of both sides, you can get around the same origin policy for server endpoints that support JSONP.
HTML5 has a new messaging system that can safely communicate data (not direct JS calls) between cooperating frames in different domains. See here and here for a description of how the HTML5 messaging works.
Yes it's a security issue because of the Same Origin Policy enforced by most browsers: http://en.wikipedia.org/wiki/Same_origin_policy .
You can look into JSONP http://niryariv.wordpress.com/2009/05/05/jsonp-quickly/ which is specifically designed to get around this.
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.
I have seen server side proxy workarounds for retrieving rss (xmls) from cross-domains. In fact this very question addressess my same problem but gives out a different solution.
I have a constraint of do not use a proxy to retrieve rss feeds. And hence the Google AJAX Feed API solution also goes out of picture. Is there a client-only workaround for this problem.
JSONP is the solution for requests that respond with JSON output. But here, I have RSS feeds which can respond with pure xml .
How do I solve the problem.
Use something like Yahoo! Pipes to serve as your proxy and translate the RSS XML into a JSON response.
Here is an article with instructions and code samples that explains how to do it: Yahoo Pipes--RSS without Server Side Scripts.
If you have control over both domains, you can try a cross-domain scripting library like EasyXDM, which wraps cross-browser quirks and provides an easy-to-use API for communicating in client script between different domains using the best available mechanism for that browser (e.g. postMessage if available, other mechanisms if not).
Caveat: you need to have control over both domains in order to make it work (where "control" means you can place static files on both of them). But you don't need any server-side code changes.
Another Caveat: there are security implications here-- make sure you trust the other domain's script!
Right now there really isn't a cross-platform solution for cross-site scripting. Do you have control or access to the RSS feeds? If so, why not simply respond with JSON and use JSONP?
There are other things coming down the pike with HTML5, like cross-site messaging (referred to as Cross-Document Messaging) that may be capable of delivering a payload of XML, but last time I checked, they hadn't even fully decided on a size limit for the messaging.
You can see the spec here: http://dev.w3.org/html5/spec/Overview.html#crossDocumentMessages
A solution for cross-domain calls without a server-side proxy is to use a SWF component.
You can script yourself one or use the readily available FLSend
The component uses ActionScript's URLRequest to call remote domains and ExternalInterface to communicate with the JavaScript methods that render your content.
The only way I can think of would be to embed a signed java applet on the webpage to retrive the xml and use javascript to interface with that. I'm not even 100% certain what the java security model is for that at present though but I think it would work.