Writing a Cross-Domain Proxy in PHP

Today I encountered a problem that many developers will likely face while building a web application with Ajax, so I wanted to share my experience with it.

The Problem:

You create a web site with the goal of consuming content from the web.  This may be in the form of a geocoding service, or perhaps a lightbox service for browsing images.  You need to load an external resource though Ajax.  The XMLHttpRequest object cannot make a connection, and you receive a javascript error, or a blank page.

The Background:

According to this excellent article on Yahoo! Developer Network, modern browsers contain security measures to prevent cross-domain scripting attacks.  This is a key security component to a safe browsing experience, albeit a slightly annoying one when we honest developers just want to have some fun on the web!

The Solution:

An intermediate script needs to be able to route requests from JavaScript to your external resource.  This concept is so widely understood it has become its own Ajax pattern, the Cross-Domain Proxy.  You can write a cross-domain proxy using the server language of your choice.  However, this is a PHP blog, so my tips for writing a cross-domain proxy will be PHP-based.

Implementation:

Proper usage of a cross-domain proxy cannot be guaranteed.  Knowing this, security checks must be put into place, not only in your client code, but in your proxy.

  1. JavaScript should call encodeURIComponent() on the path, so it is property escaped for passing to PHP.
  2. PHP does not need to call urldecode if you pass the path through the $_GET superglobal array.  From the PHP Manual:
  3. The superglobals $_GET and $_REQUEST are already decoded. Using urldecode() on an element in $_GET or $_REQUEST could have unexpected and dangerous results.

  4. If your application permits, use whitelist validation to accept only certain domains.  You can access the domain of the passed URL by a combination of the following:
    1. Create an array of accepted domains for the proxy
    2. Use parse_url with the component parameter to retrieve the host, path, or any other component of the URL passing through the proxy.
    3. Use in_array to validate the host component with the domain whitelist
    4. Repeat for other components that require validation
  5. Run the $_GET parameter retrieved through a PHP layer of escaping, as you cannot guarantee this script will be accessed only by your JavaScript client.
  6. If validation passes, access the escaped URL to complete the proxy.

That last steps was a bit…ambiguous…right?  This is because there are a couple of different ways to actually retrieve the URL in PHP.  These include (but I’m sure are not limited to) the following:

  • fopen
  • curl
  • include, require
  • etc.

For my usage, the cURL extension was the best option.  When using fopen or include/require, your php.ini must have allow_url_fopen set to 1 (true).  Some servers disable this feature as it is an invite for remote code injection.   In my case, not all testing environments enable this option.

An explanation of cURL is beyond the scope of this blog, but some good options to remember are:

  • CURLOPT_RETURNTRANSFER – Will return a string instead of writing to the PHP’s standard output if set to true.
  • CURLOPT_FOLLOWLOCATION – Will follow redirects if set to true.
  • CURLOPT_MAXREDIRS – Always use with CURLOPT_FOLLOWLOCATION to limit the number of redirects.  Remember that allowing redirects can be a security risk as well.

Hopefully, this will help you begin the process of writing a secure and robust cross-domain proxy for your Ajax-enabled applications.  Best of luck with it!

  1. No Comments