Wednesday, March 18, 2009

Same Origin Policy Needs to Evolve : X-CROSS-DOMAIN

Same Origin Policy (SOP) is an important one - it protects us from fraudulent phishing and spoofing attempts where a malicious website or trojan can emulate a website, such as an online banking site, and gain access to usernames, passwords, and other sensitive data. This type of attack has been referred to as Cross Site Request Forgeries.

But there are some instances where a web service may desire it's web service data to be shared - we need a way to indicate (to browsers) that a given web page (or webservice) may cross domain boundaries with permission from the source. The problem is that SOP (needlessly?) hampers our ability to create mashups using XmlHttpRequest object. Instead, we need a new solution - a new policy.

Crockford has been pushing for JSONRequest, a new object that can already be seen in some browsers and, according to Crockford, doesn't require Same Origin Policy enforcement because JSON data is benign.

JSON, while wildly popular, is merely a subset of Javascript's Object Literal Notation - less being able to pass functions. Crockford has omitted functions from his vision of literal notation (JSON) in order to render it powerless to execute. And, when parsed and checked as valid data by the JSONRequest object thus, an exception to the Same Origin Policy because it is supposedly "benign". It is tantamount to stealing functionality, originally given to us by the designers of Javascript and I am not in favor of it.

Instead, imagine a a world where web-service operators could mark their webservice with the header X-CROSS-DOMAIN to allow mashups to use it freely. To cover their costs of transferring vasts amount of data, some web-service operators might wish to include advertising along with it's "free" data. It is not unreasonable to suggest that a web-service operator, who must incur the data transfer cost of delivering data to various mashups, might desire to be recompensed with some advertising. Passing a self-executing function within the object literal notation (as envisioned by the creators of Javascript) might give them the ability to pass a splash advertisement on the receiving web page.

I realize that no-one likes advertising but it is a model that we have accepted in so many other mediums for free content. Nothing is for free in this world - and if we can encourage web-services with valuable content to be shared en-masse, albeit perhaps with advertising, we improve the web.

So, we don't really need another data fetching object in Javascript - XmlHttpRequest is robust and fully supported in most browsers. We don't really need JSON - object literal notation already exists. We also do not need a new policy, Same Origin Policy makes sense to protect us from websites that might spoof other websites.

What we need are Same Origin Policy exceptions. The evolved policy must allow for web servers to supply an exception header that affectively says: "This document may cross domains" so that the "REST"ful webservices can be accessed using the methods intended instead of relying on only GET (why should we be reduced to using GET when we want to POST or DELETE or PUT? Let's realize Tim Berners Lee's original vision of the web and not get side-tracked into all sorts of strange meanderings - remember SOAP?!?)

The browsers could start by implementing this exception when the expected header is found (using a HEAD request), thus allowing the content. Then application developers can make use of the header in most server handler environments. Later, server software like IIS, Apache, TomCat, etc, can allow server administrators to explicity specify which files and folders are cross domain permittable (overriding any handlers made by developers).

To illustrate it clearly, I would first like to propose the use of the non-standard header: X-CROSS-DOMAIN

The data associated with the header may be a URL for which the cross domain exception is made, or simply the text 'all' to indicate the document may cross to all domains. Further on, there might be an allowance for multiple domain listings, separated by commas. Furthermore, we might block or blacklist URLs using the minus sign in front of the offending URL. Examples might appear like this:

X-CROSS-DOMAIN: *
- requests from any domain may be permitted

X-CROSS-DOMAIN: http://reinpetersen.com, http://perukitemancora.com
- requests from reinpetersen.com or perukitemancora.com may be permitted

X-CROSS-DOMAIN: http://blog.reinpetersen.com/2008/10/interface-in-javascript.html
- requests from the specific URL http://blog.reinpetersen.com/2008/10/interface-in-javascript.html may only be permitted

X-CROSS-DOMAIN: *, -http://hackthissite.org
- all requests may be permitted except hackthissite.org

For this to work, browser support for this header must exist first. The support would be built on the XmlHTTPRequest object. Once the support in browsers exists, web developers will be able to customize their (JSON or XML) webservices to include the X-CROSS-DOMAIN header in the response in order to allow their data to be used (effectively) in mashups around the web. Mashups can continue to use the existing and robust XMLHttpRequest to GET,PUT,POST,DELETE,HEAD, and TRACE data located on various servers around the web.

As mentioned, later on, web server software can eventually include server administrators in the process, allowing them to assign X-CROSS-DOMAIN policy exceptions through standard security interfaces instead of programmatic-ally through code.

A similar measure (in intent), albeit unnecessarily verbose and potentially a massive security hole, was adopted after I wrote this article but before I published it. This article is an evolution of one I wrote many years ago [ http://slashdot.org/journal/137429/A-solution-for-cross-site-scripting ] that is no longer hosted - this article responds to some alarming trends that should be I feel should be "nipped-in-the-bud"

In version 3.5 (and greater) of Firefox, a new Request header (not a Response header such as I am proposing here) called 'Origin' permits XMLHttpRequest object to obtain cross-site data leaving the onus on the web server to enforce it (should there be need for a blacklisting of a given website). You can read more about it here: https://wiki.mozilla.org/Security/Origin and the original draft at: http://tools.ietf.org/html/draft-abarth-origin-05 and the Cross-Origin Resource Sharing working draft it was based on at: http://www.w3.org/TR/2009/WD-cors-20090317/

Because Same Origin Policy is enforced in the browser, and not at the Server, we cannot remove the enforcement at the browser unless the Server tells us this is alright. Neither can we assume that Web servers will adopt this fully, if even at all. From my experience, having written small http servers and handlers, is that there are many (1000's perhaps 10,000's) web-services that will have to re-written to support the Origin request header to deny cross-origin requests when this support was already supposed to be guaranteed by Same Origin Policy supported in all browsers.

In version 3.5 of Firefox, a hacker who has installed a trojan on your computer or has somehow lured you to his site with a crafty URL (perhaps in an email), can spoof any website that hasn't already retooled its web server to handle the Origin specification (in draft status and yet to be accepted). All because a web-service operator wanted to share his web-service to the world but didn't have the wherewithal to program a denial of service response based on Origin for unwanted abusers of the service in timely manner..

Granted, it seems Mozilla has supported the white-listing Server response header Access-Control-Allow-Origin but this is still a problems as it only a whitelist - there is no way to blacklist specific offenders. Thus, if you want to share your resource to many but you have one bugger doing dasterdly deeds with your data, you'll have to white-list everyone sharing your data - potentially a big list.

Furthermore, pushing the responsibility of deciding what can be served based on the Origin request header data onto the server is extraneous. The client (browser) is fully capable of determining what exceptions are possible based on the server's list of exceptions (or non-exceptions) to Same Origin Policy. Remember, we are trying to push processing out to the leaf nodes in this age of increasing computing power in the hands of users and increasing demand on servers.

While attempting to solve the same problem, Mozilla has followed a route (CORS) that is rather backwards in regards to sharing resources across domains. The onus remains on the browser to maintain Same Origin Policy and the only exceptions that should be made should be dictated by Servers, ideally through a header as I have demonstrated in this article.

What the 'Origin' header really does is force web servers to process the header and decide if it can share the resource or not. Rather, the solution should be an 'opt-in', as I have demonstrated with X-CROSS-DOMAIN, where a web server can claim a given resource may be freely mashed (or specifically denied) into other websites (perhaps with advertising intact) and the browser can loosen the Same Origin Policy only when it has this permission within the header of a resource.