Specifications/Cross Domain Access Policies
Note: This is a work in progress
One of the oldest security models 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 these types of 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 other domains can access them.
Public web services can be consumed from any domain using server-side scripting. The reason browsers cannot allow the same behavior is because they create a new problem which server-side scripts do not have, namely, allowing the circumvention of firewalls such as those 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, then a malicious Internet site visited by a firewall user could access web services inside the firewall (where such services usually assume they can be accessed only from behind the firewall). For example, a company may have an internally public web service that queries into its employee database.
The goal of this document is to standardize these two approaches into a more generic model so that it can cover more use cases.
It is also important to note that this does not only apply to "scripting" languages. For example, W3C's XForms allows sending and/or retrieving of XML without any scripting. Even just being able to send a SOAP request (which can be construted in XForms) cross-domain may be unsecure if the service does not expect being called from outside the firewall. Web Forms 2.0 from the WHATWG allows sending of XML in a restricted fashion, which for example won't allow faking a SOAP request.
Controlling Cross-Domain Access on the Server
Both solutions used an XML file in the root directory of the web service 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 were found, then access would be denied, ensuring that no existing service could 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:
<cross-domain-policy xmlns="http://somedomain/2005/cross-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 both 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>.
The policy file works like a whitelist. It lists which outside domains have access to web services on this domain and what types of services they may consume. The allow element is used for this, and the domain is specified in its 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. If the implementor is IDN aware, then the from attribute should be IDN aware as well.
For enhanced security, the allow element can also specify which subdirectory on the current domain this rule applies to, using the to attribute. So if to is set to service/, then that rule only applies for services located in that directory.
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.
|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)|
The optional delegate attribute (default is false) on the allow element allows the policy file to redirect the client to another policy file. In other words, if an outside (but allowed) domain is trying to access a web service on a subdirectory on the current domain, then the client should look for a policy file in that subdirectory. If no policy file is found in the subdirectory, then access is rejected and policy processing ceases.
Given this policy file at http://www.company.com/cross-domain-policy.xml:
<cross-domain-policy xmlns="http://somedomain/2005/cross-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 anyway and access is rejected.
- 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 where 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 its data.