Facebook, MySpace, and crossdomain.xml

06 Nov 2009

Thanks to the recent recurrence of a vulnerability I wrote about a few years ago and a gentle prod from Simon, I decided it would be good to write about the dangers of cross-domain Ajax with Flash again.

If you read about this story on TechCrunch, note that the "write up explaining all the details" is about an unrelated vulnerability.

I'll try to briefly explain the problem and then show how it relates to Facebook and MySpace. For more background information, please refer to these prior posts:

Web technologies that abide by the same-origin policy cannot reside on one site and interact with another. To be a little more specific, if you visit my site, I can't make you update your status on Twitter . If I want to try, I need to get you to send an HTTP request similar to the following:

  1. POST /status/update HTTP/1.1
  2. Host: twitter.com
  3. Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  4. X-Requested-With: XMLHttpRequest
  5. Referer: http://twitter.com/
  6. Content-Length: 66
  7.  
  8. authenticity_token=snuffleupagus&status=@shiflett+made+me+do+this.

If I use JavaScript to do this, the request is sent from you to Twitter, so it also includes any cookies Twitter uses to identify you. (I did not include the Cookie header in this example, because it's really long.) Would this work? Luckily, no, but only because I have to know the value of your authenticity_token, Twitter's anti-CSRF token. (Read my article on CSRF for more information about cross-site request forgeries and anti-CSRF tokens.)

To work around this safeguard, I need to get your anti-CSRF token. If you visit Twitter yourself and view source, you can see it:

  1. <input name="authenticity_token" value="snuffleupagus" type="hidden" />

This token is yours and won't work for anyone else. If I want to forge a request from you, I need to know what your token is. Because you can view source and see your token, you know it's included in the response. I can use JavaScript to send a request from you, but is there a way I can also read the response?

Yes, there is. Meet XMLHttpRequest(), often abbreviated as XHR, the method most closely associated with Ajax. If I use XHR to send a request from you (to Twitter) and read the response, I can find your token and use that to update your status. Would this work? Luckily, no, because XHR abides by the same-origin policy. I can only use XHR to send requests that are considered to be within the same origin, so I cannot use XHR on my site to send a request (from you) to Twitter, a different site.

Enter crossdomain.xml. Flash supports cross-domain Ajax using an opt-in model, where the receiving site has to give permission. For example, I could make you update your Twitter status if Twitter’s cross-domain policy file let me:

  1. <?xml version="1.0"?>
  2. <!DOCTYPE cross-domain-policy SYSTEM
  3. "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
  4.  
  5. <cross-domain-policy>
  6.   <allow-access-from domain="shiflett.org" />
  7. </cross-domain-policy>

Luckily for you, Twitter doesn't trust me. More accurately, they don't force you to trust me. This is where open cross-domain policy files like the following are dangerous:

  1. <?xml version="1.0"?>
  2. <!DOCTYPE cross-domain-policy SYSTEM
  3. "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
  4.  
  5. <cross-domain-policy>
  6.   <allow-access-from domain="*" />
  7. </cross-domain-policy>

A few days ago, Yvo Schaap realized that Facebook Connect not only had an open cross-domain policy file, but also had a complete running copy of the Facebook site. (As evidence, here's the home page within the www.connect.facebook.com domain. If you're logged in, you'll be recognized.)

In other words, Yvo found another site with the same vulnerability that has plagued so many others, including Flickr, YouTube, Yahoo, and Adobe. (Cue Queen.)

If someone can update your status, simpler exploits are also possible. For example, someone can effectively browse Twitter as you, possibly reading private updates from your friends with protected accounts. Because Facebook was vulnerable to this type of exploit, your personal information could have been exposed if one of your friends was exploited, even if you weren't.

MySpace made a similar mistake. Although their cross-domain policy file was not open, it trusted farm.sproutbuilder.com (Sprout Builder), a site that allows users to upload their own .swf (Flash) files, thereby gaining complete access to MySpace.

I'm glad Yvo waited until these vulnerabilities were fixed before blogging about them. Unfortunately, I already let the cat out of the bag a few years ago. Hopefully more people will pay attention this time and tread carefully when using crossdomain.xml. Adobe's own site has finally been fixed, so you no longer have to ignore the hypocrisy of their usage recommendations:

Using a cross-domain policy file could expose your site to various attacks. Please read this document before hosting a cross-domain policy.

Thanks to Jon, Sean, and Simon for reviewing a draft of this post.