We have a need to consume an external REST Api and dynamically update content on our website and have ran into the age old problem of cross site scripting and Ajax.
I've read up on JSONP however I don't want to go down that route in a million years as it seems like really a rather dirty hack.
As a solution to this issue is it "right" and "proper" to have a local service that acts as a proxy for any requests to an external Api? So on the client there would be an Ajax call to ../RestProxy/MakeRequest passing it the details of the request it needs to make to the external api, it performs the request and returns anything passed back.
Any thoughts would be appreciated.
There are three ways to do this:
1. JSONP
This is accepted by many popular APIs and frameworks. JQuery makes it easy. I would recommend this.
2. Proxy
Works pretty much as you described. Adds an extra step and server code and server load for you. However, it does allow you to filter or otherwise manipulate the results before sending them to the client.
3. Rely Access-Control-Allow-Origin
This is a header that the server can set to allow you to read json directly from their server even though you aren't on the same domain. This eliminates the need for the jsonp hack, but it requires the the server be setup to support it and it requires a web browser that supports it.
Access-Control-Allow-Origin is supported in:
IE8+
Firefox 3.6+
Safari 4.0+
Chrome 6+
iOS Safari 3.2+
Android browser 2.1+
If you need to support IE7, then this option isn't for you.
Related
As I found, it is possible to manipulate and change Ajax code in browser console by client. For example, Ajax wants to call a method and pass id to controller. As I mentioned above, how we can secure our code from interference by client?
Thank you all
Security must always be implemented on the server side, because anything you do on the client side can be ignored, overstep, modified, etc very easily. In fact, anyone can use software like Postman to make a completely custom HTML request to any server.
Don't ever rely on any client-side software in terms of security for your server. If you want keep your server safe, then make a safe server.
First I'm not in the web side of our world, so be nice with the backend guy.
A quick background : For a personal need I've developped a google chrome extension. They are basically a webpage loaded in a chrome windows and... yeah that's it. Everything is on the client side (scripts, styles, images, etc...) Only the data are coming from a server through ajax calls. A cron job call a php script every hours to generate two files. One, data.json contains the "latest" datas in a json format. Another one hash.json contain the hash of the data. The client chrome application use local storage. If the remote hash differ from the local one, he simply retrieve the data file from the remote server.
As I have a BizSpark account with Azure my first idea was : Azure Web Site with php for the script, a simple homepage and the generated file and the Azure Scheduler for the jobs.
I've developed everything locally and everything is running fine... but once on the azure plateform I get this error
XMLHttpRequest cannot load http://tso-mc-ws.azurewebsites.net/Core/hash.json. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:23415' is therefore not allowed access.
But what I really can't understand is that I'm able (and you'll be too) to get the file with my browser... So I just don't get it... I've also tried based on some post I've found on SO and other site to manipulate the config, add extra headers, nothing seems to be working...
Any idea ?
But what I really can't understand is that I'm able (and you'll be
too) to get the file with my browser... So I just don't get it
So when you type in http://tso-mc-ws.azurewebsites.net/Core/hash.json in your browser's address bar, it is not a cross-domain request. However when you make an AJAX request from an application which is running in a different domain (http://localhost:23415 in your case), that's a cross-domain request and because CORS is not enabled on your website, you get the error.
As far as enabling CORS is concerned, please take a look at this thread: HTTP OPTIONS request on Azure Websites fails due to CORS. I've never worked with PHP/Azure Websites so I may be wrong with this link but hopefully it should point you in the right direction.
Ok, will perhap's be little troll answer but not my point (I'm .net consultant so... nothing against MS).
I pick a linux azure virtual machine, installed apache and php, configure apache, set some rights and define the header for the CROS and configure a cron in +/- 30minutes... As my goal is to get it running the problem is solved, it's running.
I have recently been experimenting with building a cross domain web api, and wow has it been a bumpy journey. I have not had any problems with modern browsers such as Chrome, FF and Safari. The problem is with IE, which requires you to use XDR as opposed $.ajax when making cross domain calls. First Question: If I was using Backbone.js, what is the recommended way of making cross browser and cross domain ajax calls?
Another problem I had with IE was that when you make cross domain ajax requests, IE has a bunch of restrictions and limitations such as "Only text/plain is supported for the request's Content-Type header" - a link. Therefore in my case, I was unable to bind to my model using the MVC C# framework, unless I bind it manually.
Anyway my second and last question is: How do companies like Instagram, Facebook, and Twitter go about building their API's? I am not looking for a complete guide, but just want to know how difficult it is.
JSONP
The current standard is using JSONP. It is basically a trick to send a JSON payload wrapped in a single JavaScript function, the browser treats it like a script file and executes it.
CORS
Moving forward the way to go is CORS. Sadly browser support (IE) isn't there yet and there are still some implementation differences between the modern browsers that do implement it.
HTTP Method Overloading
Some APIs overload GET and POST request using X-HTTP-Method-Override: PUT or ?_method=PUT.
easyXDM
A number of API providers implement easyXDM. This tends to be used more when they provide a JavaScript API or widget API where developers load their JS and integrate it directly in to the frontend code.
The parts
I am developing against two Pylons servers and testing locally. One server is on port 5000 and is the called server. The other is on port 7000. The latter creates a cookie that specifies the same domain as used by the former server. Essentially, the first server uses credentials provided by the second server to impersonate the user.
The first server expects to find an auth token (a cookie, really) in its response.environ at run time. When I authenticate on the server on port 7000 and browser to a service on port 5000, the latter server uses the cookie created by the former and the app works.
The fly in the ointment is that the first server creates an HTML5 app that uses an ajax call to the second server, and I cannot get the cookie to be included in the ajax call. I believe that Chrome (the browser we are using/requiring for HTML5 support reasons) refuses to send the cookie for cross domain reasons: going from foo.net:7000 to foo.net:5000 is considered cross domain.
Oh, and the ajax call is through jQuery.
The question
Is there any way to make an ajax call from an HTML5 app created on a port in the same domain to a server in the same domain but a different port?
What I've tried or discard out of hand
I do not believe I can use dynamic script tag insertion because I am making the call from javascript and the HTML is generated on the client at runtime from other javascript. At least, I don't think that is a desirable solution.
I don't believe Access-Control-Allow-* is applicable because I am going from client to server, not the other way.
I've seen this on jQuery and ports in ajax calls. I've seen this, too.
I know about the same-origin policy.
And this does not work.
Agree with Michael that the simplest solution is JSONP. But even in JSONP you need to configure your server such that it supports JSONP. Many Servers deny this to keep their data secure and sound. JSONP expect your server to send data in the format that can be evaluated as the valid JSON. But its not the case in every JSONP Request and response. So, just watch out for that.
The absolutely simplest solution to this is to use JSON/P. I wish there were an easier, softer way to accomplish this, but I certainly haven't found one.
I've created a RESTful API that supports GET/POST/PUT/DELETE requests. Now I want my API to have a Javascript client library, and I thought to use JSONP to bypass the cross-domain policy. That works, but of course only for GET requests.
So I started thinking how to implement such a thing and at the same time trying to make it painless to use.
I thought to edit my API implementation and check every HTTP request. If it's a JSONP requests (it has a "callback" parameter in the querystring) I force every API method to be executed by a GET request, even if it should be called by other methods like POST or DELETE.
This is not a RESTful approach to the problem, but it works. What do you think?
Maybe another solution could be to dynamically generate an IFrame to send non-GET requests. Any tips?
There's some relevant points on a pretty similar question here...
JSONP Implications with true REST
The cross-domain restrictions are there for a reason ;-)
Jsonp allows you to expose a limited, safe, read-only view of the API to cross domain access - if you subvert that then you're potentially opening up a huge security hole - malicious websites can make destructive calls to your API simply by including an image with an href pointing to the right part of the API
Having your webapp expose certain functionality accessed through iframes, where all the ajax occurs within the context of your webapp's domain is definitely the safer choice. Even then you still need to take CSRF into consideration. (Take a look at Django's latest security announcement on the Django blog for a prime example - as of a release this week all javascript calls to a Django webapp must be CSRF validated by default)
The Iframe hack is not working anymore on recent browsers, do not use it anymore (source : http://jquery-howto.blogspot.de/2013/09/jquery-cross-domain-ajax-request.html)