Make cross-origin HTTP requests with XMLHttpRequest



In the early years of the Internet, it was possible to breach users security by using of JavaScript to exchange information from one website to another that has less reputation.

Therefore, all modern browsers implement the same origin policy that prevents attacks like cross-site scripting.

However, sometimes cross-origin HTTP request is a must-have requirement for a web application. This article will discuss about methods of how to deal with cross-origin HTTP requests. Lets start with some background information.

Origin policy

The algorithm used to calculate the "origin" of a URI (Uniform Resource Identifier) is specified in RFC 6454.

There are two different cases:
  1. Absolute URIs, the origin is the triple {protocol, host, port}
  2. If the URI does not use a hierarchical element as a naming authority (RFC 3986) or if the URI is not an absolute URI, then a globally unique identifier is used.
Two resources are considered to be of the same origin if and only if all these values are exactly the same.

The table below illustrates a check against the URL "http://www.example.com/pages/index.html":
URL to compare Result Why?
http://www.example.com/pages/index2.html ok Same host and protocol
http://www.example.com/pages2/index.html ok Same host and protocol
httpː//username:password@http://www.example.com/pages/index.html ok Same host and protocol
http://www.example.com:8080/pages2/index.html fail Same host and protocol, but different port
https://www.example.com/pages/index.html fail Different protocol
http://sub.example.com/pages/index.html fail Different host
http://example.com/pages/index.html fail Different host
http://www.example.com:80/pages/index.html - (Different port) Depends on the browser implementation


If the policy cannot be applied, the web browser will respond with an exception message, such as the following:

XMLHttpRequest cannot load ...
Cross origin requests are only supported for HTTP.
Uncaught NetworkError: A network error occurred.

Relaxing the same origin policy

Here are some techniques to relax with origin policy:
  • JSONP. If the requirement was to get only the data from a different domain, then a JSONP request is the best choice. JSONP includes external data via the <script> tag.
  • Cross origin resource sharing. This extends HTTP with a new origin request header and a new Access-Control-Allow-Origin response header. This article describes how to enable CORS.
  • Disable web security (for development mode only). If an application is under development, the web security can temporarily disabled for the web browser. While the web browser is in an unsecured mode, it is highly recommended not to surf on public Internet pages (since the browser is vulnerable for all cross site scripting attacks). See "Disable web security for a web browser".
  • Reverse Proxy. A reverse proxy (or gateway), by contrast, appears to the client just like an ordinary web server. No special configuration on the client is necessary. The client makes ordinary requests for content in the name-space of the reverse proxy. The reverse proxy then decides where to send those requests, and returns the content as if it was itself the origin. See "Setup a reverse proxy".
  • Whitelist (PhoneGap). If a web application is deployed to a mobile device with PhoneGap the domain can whitelisted (Whitelist Guide).

Disable web security for a web browser

For Google Chrome, the following command must executed in Terminal (browser must be closed):

/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --disable-web-security

Setup a reverse proxy

Nowadays there are many http servers on the market, however this article focuses on how to configure a reverse proxy with XAMPP.

Install XAMPP

XAMPP is a free and open source cross-platform web server solution stack package, consisting mainly of the Apache HTTP Server, MySQL database, and interpreters for scripts written in the PHP and Perl programming languages.

You can download XAMPP here http://www.apachefriends.org/en/xampp.html.

Configure a virtual host

A virtual host gives you the possibility to run several name-based web applications on a single IP address.

Configuring the virtual host on your web server does not automatically cause DNS entries to be created for those host names. You can put entries in your hosts file for local testing.

Make a local host file entry

  1. Open your Terminal.
  2. Type: "sudo vi /private/etc/hosts" to open the host file.
  3. Add the following entry "127.0.0.1 local.app.com" to the end of this file. You can modify this domain name to your needs.
  4. Save the file and close it.

Configure XAMPP

  1. Open your Terminal.
  2. Open the XAMPP virtual host file. "sudo vi /Applications/XAMPP/etc/extra/httpd-vhosts.conf"
  3. Add the following virtual host entry to the end of this file:
<VirtualHost *:80>
  DocumentRoot "/Volumes/workspace/myHtml5App"
  ServerName local.app.com
  ProxyPass       /service.php       http://yourExternalHost.com/communication/service.php
</VirtualHost>

Short explanation:
  • "*:80" Listen for virtual host requests on all IP addresses.
  • "DocumentRoot" Destination of the web application on the filesystem.
  • "local.app.com" Server name, must be the same name as in the host file above.
  • "ProxyPass" Proxy path holds the service address.
Before you restart the server, make a quick check to the httpd.conf file. ("sudo vi /Applications/XAMPP/etc/httpd.conf").

Make sure that the following entries are not commented with a "#"
  • "Include /Applications/XAMPP/etc/extra/httpd-vhosts.conf"
  • LoadModule proxy_module modules/mod_proxy.so
  • LoadModule proxy_connect_module modules/mod_proxy_connect.so
If all is fine, restart your server.

If you call "local.app.com" in your browser, the web application should open. But you will still receive a cross origin policy exception, because your web application still sends the requests to "http://yourExternalHost.com/communication/service.php".

To fix this, replace the URL "http://yourExternalHost.com/communication/service.php" with "local.app.com/service.php" in your web application.

10 comments: