Specifications/Cross Domain Access Policies
Note: This is a work in progress
Introduction
One of the oldest security model in browsers today is the cross-domain policy. Browsers restrict pages from accessing data from pages on other domains. However, modern browsers can now consume services, such as XML datasources or SOAP, and such public web services are being hampered by the strict cross-domain security model. This document attempts to specify a new model, by which domains can specify which which domains can access them.
Problem
Public web services can be consumed from any domain using server-side scripting. The reason browsers cannot allow the same is because they create a new problem which server-side scripts do not have, namely allowing the circumvention of firewalls, such as the ones used by corporate intranets.
A browser being used behind a firewall can connect to both the internet and the intranet. If browsers allowed websites to access any domain, a malicious internet site, when visited by a firewall user, could then access web services inside the firewall, who usually assume that they can only be accessed from behind the firewall. For example, a company may have a internally public web service into its employee database.
Two independant groups ended up implementing a solution in a very similar way: allow the web service domain to specify who may access it, and then the client (such as a browser) makes sure the cross-domain call is permitted. Macromedia implemented this for Flash 7, and Netscape implemented this for consuming XML Web Services (SOAP/WSDL) from JavaScript in Mozilla-based products.
The goal of this document is to standardize the two approaches and make it more generic, so that it can cover more use cases.
Controlling Cross Domain Access on the Server
Both solutions used an XML file in the root directoy of the webservice provider. For example, if one were trying to load http://www.foo.com/service/foo.xml, the policy setting XML file would reside at http://www.foo.com/. Note that this policy file would not affect services provided on subdomains, such as http://service.foo.com/. If no file was found, then access was denied, ensuring that all existing services could not be called without specifically allowing it.
The Policy File
The policy file is named cross-domain-policy.xml, and here is a sample of how it should look:
<?xml version="1.0"?>
<cross-domain-policy xmlns="http://somedomain/2005/x-domain-policy">
<allow type="any" from="*.company.com" delegate="false"/>
</cross-domain-policy>
The root node is called cross-domain-policy, and it contains as many allow elements as needed. The client walks the allow elements until it finds one that matches the request type and the caller's domain. If no match is found, the cross domain request is denied by the client. The DTD for the file:
<!ELEMENT cross-domain-policy (allow*)>
<!ELEMENT allow EMPTY>
<!ATTLIST allow type|from|delegate CDATA #IMPLIED>.
Whitelisting
The policy file works like a whitelist. One lists which domains may access web services on this domain, and what type of services may be consumed from the allowed domain. The allow element is used for this, and the domain is specified in it's from attribute. Full domains may be used, such as www.foo.com, or wildcarded ones, such as *.foo.com or even just * to allow any domain. If no from attribute is set, then any domain is allowed.
Types of Services
The type of service allowed is set via the case-sensitive type attribute on the allow element. The default type is "any", which allows any service to be accessed from that domain.
| Type | Description |
| any (default) | Allows any service to be accessed |
| xml | Allows sending and loading of XML, such as XMLHttpRequest requests. |
| soap | Allows talking to SOAP/WSDL XML Web Services. |
| load | Allows only loading of data from that domain. |
| save | Allows only sending of data from that domain. (save used because of DOM 3 L/S, not sure if a good idea though) |
Delegation
The optional delegate attribute (default is false) on the allow element allows the policy file to tell the client that if the webservice the matched domain is trying to access lives in a subdomain on the current domain, then it should look for a policy file in that subdomain. If no policy file is found, access is rejected and the policy file is no longer processed.
Given this policy file at http://www.company.com/cross-domain-policy.xml:
<?xml version="1.0"?>
<cross-domain-policy xmlns="http://somedomain/2005/x-domain-policy"> <allow type="xml" from="*.foo.com" delegate="true"/> </cross-domain-policy>
If http://bar.foo.com tries to load the XML file http://www.company.com/service/foo.xml, the client will look for http://www.company.com/service/cross-domain-policy.xml. If found, that policy file is proccessed and the current policy file is discarded. If the file is missing, the current policy file is discarded as well and access is rejected.
Concerns
- In a multi-user system, the root node needs the policy file and it also needs to delegate so that the users can regulate access. Should we perhaps put the file in the same subdirectory as the service is located? If we did, would this be a security risk? I would think not, since if the user got compromised, only his web service would be accessed, and the compromiser would already have access to all it's data.