I'm new to AJAX and I have what I think is a simple question. I know you can create a page that will respond to an AJAX call. Is it possible to just get any page with an AJAX call?
So I mean to say, can I do anything with an AJAX call that I could do with a URL?
EDIT #1
Thanks for all the responses! Really helped clarify!
Yes and no.
AJAX is a powerful mechanism by which you can retrieve and/or load data into the DOM in a flexible manner. You can do things like grab the content of another page and display all or portions of it on your page. There is a catch however.
Due to security reasons, you cannot depend on being able to make an AJAX call in a cross-domain manner unless the server on the other domain is properly configured. This is known as Cross-Origin Resource Sharing (CORS). You can read more about that here - http://en.wikipedia.org/wiki/Cross-origin_resource_sharing
Alternatively, some servers will expose API's that work with JSONP (JSON with Padding), which is a sort of workaround for the Same Origin Policy (SOP) that normally prevents cross-domain requests of this nature. In JSONP, the remote endpoint in essence wraps the response in a javascript function. You can read more about JSONP here - http://en.wikipedia.org/wiki/JSONP
You are limited to requests within the same domain, unlike a normal URL. There are ways around it using CORS or JSONP in that case.
http://en.wikipedia.org/wiki/Cross-origin_resource_sharing
No.
One example is that you can't use AJAX to upload or download files. One workaround for this is to target the upload or download to a hidden iframe and poll that frame for a response. Update: it seems some support for this is part of HTML 5 (see https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications).
A second example is navigating the user to another page. You can load a second page and replace the contents of the window with it, but the URL will still be the original page (the "refresh" and "back" features of the browser will behave accordingly).
A third is cross-domain requests. AJAX calls are limited to the domain the page originated from.
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.
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.
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 set up a js fiddle - just a simple jquery load function that loads the content of a url into a div, but it doesn't work. If I access the URL directly, it works fine. Any ideas what might be going wrong?
http://jsfiddle.net/heaversm/jLaPr/
The problem is that the url is on another server and you can't access it. If you want to call it, you should use $.ajax() and set the crossDomain option to true
Taken from the documentation of load():
Due to browser security restrictions, most "Ajax" requests are subject to the same origin policy; the request can not successfully
retrieve data from a different domain, subdomain, or protocol.
Due to browser restrictions, most Ajax requests are subject to the "same origin policy". That means that in most cases, you can’t use jQuerys ajax methods to fetch data from external domains without using a Proxy, YQL, JSONP or equivalent technique to get around this.
You should consider using this:
https://github.com/jamespadolsey/jQuery-Plugins/blob/master/cross-domain-ajax/jquery.xdomainajax.js
Using this plugin should allow the ajax example in your question.
Another option is to use a server-side proxy and then request that page using ajax. If your server can run PHP, try googling for something like "php ajax proxy" and you’ll get plenty results.
It's definitely a browser restriction (http://api.jquery.com/load#notes-0):
Due to browser security restrictions, most "Ajax" requests are subject to the same origin policy; the request can not successfully retrieve data from a different domain, subdomain, or protocol.