Any web mashups, by definition, require cross-domain calls. Those cross-domain calls may happen on the client (in the browser) or on the server. Regardless of the client technology (AJAX, Flash, Silverlight, etc.), cross domain calls on the client are always more complex that server-side cross-domain calls, and for good reason. It's tricky in AJAX, and it's downright difficult in Silverlight. You'll know that Silverlight development has become more widespread when you hear a lot more complaints about this problem.
I previously wrote about using a static port to eliminate this problem when you're calling back to your own server but Silverlight is detecting a cross-domain call. That's caused by the ASP.NET Development Server running the different projects on different ports (e.g. website on localhost:1234 and webservice on localhost:5678), and you can work around it by just putting the website and webservice in one project with a static port. However, there are plenty of times when you'll want to make a cross-domain call, so we've got to get this figured out.
While helping Rob Conery work through some problems connecting to Amazon Web Services this past week, I wrote up some notes on the issue.
Silverlight intentionally blocks cross domain access
Silverlight intentionally forbids cross domain access, so unless webservices.amazon.com served up the page with the Silverlight control, it’s not going to allow access. That’s a pain from a developer point of view, but from a security point of view it makes complete sense. Otherwise a the Silverlight control could be used to turn a user’s browser into a “zombie” which could roam the entire Internet and local intranet without the end user’s knowledge, doing all kinds of bad things (posting spam on forums, DDOS attacks, modify the local router via web access, etc.).
It's important to understand that this is an even worse case than a simple cross-site scripting (XSS) attack, which steals information from one site to pass to another. In addition to information security issues, a cross-domain vulnerability is like an unpatched virtual machine running on a patched host, since malicious net access code would be more like an out of control virus with full Internet access.
A simple proxy through XmlHttp isn't likely to work
XmlHttp in both Firefox and IE7 (and XmlHttpRequest in IE6) are pretty locked down by default, so it’s hard to come up with a cross browser solution that will work on a default browser configuration. For example, Firefox only allows it if the script is signed, and IE7 applies security zone policies. It's hard to find a simple cross browser solution here.
Server-side proxies are a simple solution
You can use a server side proxy, of course, which gets around all these restrictions because Silverlight is calling back to the originating domain.
The JSONP workaround
What I think Microsoft should do
The Silverlight team should do one or more of the following:
- Document this more, preferably in the Silverlight documentation on MSDN
- Add a client configurable whitelist of domains to which cross-domain calls are allowed
- Have a list of "certified" safe domains to which cross-domain calls are allowed (Microsoft, Google, Amazon, Flickr, del.icio.us, etc.).
- Offer a proxy service, perhaps reimbursed by the target domains
UPDATE: I heard there will likely be a solution of some kind to this problem in a forthcoming Silverlight release.
A pretty good article on JSONP with a sample which hits AWS: http://www.devx.com/webdev/Article/30860/1954
A sample which hits AWS via JSONP (bonus points for using XSLT to convert AWS XML responds to JSON, which isn’t as useful for you since in Silverlight XML’s easier to read than JSON): http://www.kokogiak.com/gedankengang/2006/05/consuming-amazons-web-api-directly.html
My previous blog entries on the topic - http://weblogs.asp.net/jgalloway/archive/2007/06/14/calling-an-asmx-webservice-from-silverlight-use-a-static-port.aspx, http://weblogs.asp.net/jgalloway/archive/2007/05/08/silverlight-cross-domain-access-blocked-use-a-server-side-proxy-or-xmlhttprequest.aspx