Workaround for AJAX Cross-Domain Post Restrictions

We recently developed an application that requires our partners to incorporate a piece of our html code in their browser page. This component would be responsible for collecting information and posting it back to our site via ajax for validation. The inclusion of our code would be done using server side includes so as to avoid using frames and for security reasons. The end result would be that the partner would send their page with our html component included in it back to the browser; the browser would show the partner url. All in all very unobtrusive.

Once the user enters their information into a form on that page, our script would take over and submit the information to our server, at a different domain, via ajax. Our server would return the result of the validation of the information.

There is only one very big problem with this approach – browsers currently consider such a cross-domain ajax post a vulnerability. Browsers will not allow an ajax post to a domain that is different than the domain currently in the browser location. Check out the same origin policy.

I won’t dive into an argument for or against allowing cross-site ajax posting here, instead I’ll just provide the mechanism we used to perform this post without using the standard ajax method, eg. XMLHttpRequest.

At a high level, what we do is this:

  • Capture user input on the client using javascript.
  • Construct a url containing our user input validation resource, a random identifier, and the query parameters from the user input.
  • Create a new “<script>” DOM node with a src reference to the constructed url. This results in an implicit request being sent by the browser for the javascript source.
  • Our server handles the request, validates the input, and returns pure javascript as a response. Embedded in this javascript is a function which will call javascript already sitting on the browser once it is loaded.
  • Once the javascript response is loaded into the DOM by the browser, the script is executed – performing whatever processing is necessary at the client.

Below is the main script. This code handles user input and submits the input asynchronously by inserting a new script node into the DOM. This forces the browser to request the src for that script node. On the server, that request is handled, the input is validated, and javascript is returned back to the client which just executes the ‘responseCallback’ method.

Main Script:

<script type="text/javascript" language="javascript1.2">// <![CDATA[
// Validation url
var url = "http://your.host.com/validationresource";

// Callback method
var callbackMethod = null;

// Call this to kick off asynch server validation
function submitRequest(input1, input2, callback) {
  // Perform client side validation of input first
  // validateInput(input1, input2)    
  
  // Assign callback
  callbackMethod = callback;
  try {
    // Find dom node where we'll insert our "script" node
    var dynamicjs = document.getElementById("dynamicjs");

    // Remove if it already exists
    if (dynamicjs != null) dynamicjs.parentNode.removeChild(dynamicjs);

    // Create url with params and timestamp to prevent caching. I believe
    // the timestamp must be part of the resource url to force the browser
    // to reload the javascript
    var params = "input1=" + input1 + "&input2=" + input2;
    var jsurl = url + (new Date()).getTime() + "?" + params
    var fileref = document.createElement('script');
    fileref.id = "dynamicjs";
    fileref.setAttribute("type", "text/javascript");
    fileref.setAttribute("src", jsurl);

    // Insert the node which results in a browser request to the server
    if (typeof fileref != "undefined") {
      document.getElementsByTagName("head")[0].appendChild(fileref);
      return;
    }
  }
  catch(err){}  
}
// Callback method to be executed once a response comes back from
// the server validation
function responseCallback(response) {
  eval(callbackMethod(response));  
}
// ]]></script>

Below is the server code that handles the request, validates the input from the client, and returns a response that is basically a javascript file. That javascript file contains a script that calls the ‘responseCallback’ method above with the result of the input validation.

Server Code (Java):

ServletOutputStream out = response.getOutputStream();
String result = "ok";
response.setContentType("text/javascript");
response.setHeader("Cache-Control", "no-cache");
out.write(("responseCallback('" + result + "');").getBytes());
out.flush();

1 Comment

  1. I think we do need to have the discussion of cross-site ajax posting here. Clearly dynamicjs becomes a memory hog in one of the choices. While you may work under the Bill Gates assumption that hardware resources are infinite, I prefer to write crisper, more efficient code in all circumstances out of self-respect.

Leave a Reply

Your email address will not be published. Required fields are marked *