84

I was browsing Facebook's documentation reading about canvas applications and I came across an example application: http://developers.facebook.com/docs/samples/canvas. As I read through their example, however, I got very confused about their use of cookies in the iframe application.

A little backstory...

I had already played around with using iframes for embeddable widgets (unrelated to Facebook) and I found out a few browsers (Chrome, Safari, etc.) have strict cookie policies and don't allow cross-domain cookies set in iframes (Firefox, on the other hand, allows iframes to set cross-domain cookies in iframes). For example, if foo.com has an iframe with src="http://bar.com/widget" the iframe widget will not be able to set any cookies for bar.com and therefore will have trouble persisting state within the iframe: bar.com will interpret every request (including ajax requests) from the widget as a fresh request without an established session. I struggled, and found a way around this by using JSONP and javascript to set cookies for foo.com instead...

... and so?

Well, I was looking at the example canvas iframe Facebook application and I noticed that their application (hosted on runwithfriends.appspot.com) is able to set a cookie, u, with the current user's id along with a few other parameters for the runwithfriends.appspot.com domain. It sends this cookie with every request... and it works in both Chrome and Firefox! WTF? How does Facebook get around the cross-domain cookie restrictions on Chrome?

(I already know the answer now, but I thought this might be helpful for anyone struggling to figure out the same thing -- I'll post the answer below.)

Aaron Gibralter
  • 4,773
  • 3
  • 35
  • 50
  • 2
    Update: the latest versions of some browsers (Safari v6.x+ on OS X, Safari on iOS 6+, and I assume Chrome and FF soon) do not allow for setting of cross-domain cookies anymore, even on post-to-iframe requests. – Aaron Gibralter Jun 18 '13 at 19:21

1 Answers1

89

So the iFrame isn't actually setting the u cookie for the runwithfriends.appspot.com domain. What Facebook does is it creates a form, <form action="runwithfriends.appspot.com/..." target="name_of_iframe" method="POST"> and uses javascript to submit the form on page load. Since the form's target is the iframe, it doesn't reload the page... it just loads the iframe with the POST's response. Apparently even Chrome and other browsers with strict cookie policies set cookies for cross domain requests if they are POST requests...

Aaron Gibralter
  • 4,773
  • 3
  • 35
  • 50
  • 3
    I created a proof of concept sinatra app to demonstrate how this works: https://github.com/agibralter/iframe-widget-test – Aaron Gibralter Feb 01 '11 at 21:56
  • Hey Aaron, Do you have a pure Javascript version of this code/demo please? – lshettyl Jul 27 '11 at 13:57
  • 2
    @LShetty -- sorry, I'm not sure I understand what you mean... pure Javascript? The Ruby portion of the demo acts as the web server... do you mean you want to see the demo written in Node.js? – Aaron Gibralter Jul 28 '11 at 03:34
  • I has same hard time LShetty had. I don't get what your code is for. what about a php solution, i don't get form your code where's the beef.. – Francesco Feb 07 '12 at 20:38
  • 6
    @Seth I haven't checked in a while, but the latest version of Safari (v6.0/iOS6 and I assume soon Chrome and FF) don't allow this trick anymore: the cookies don't get set on post-to-iframe requests. I'd have to look into how Facebook is handling this for new browsers. For now, localStorage seems like a good alternative method. – Aaron Gibralter Jun 18 '13 at 19:19
  • Here is a little post about it http://nfriedly.com/techblog/2010/08/how-facebook-sets-and-uses-cross-domain-cookies/ – Serge Kvashnin Sep 14 '14 at 08:00
  • 2
    Let me just tell you, that if you have "disable third party cookies" that workaround iframe thing will stop working i believe. – Miguel Jun 03 '16 at 17:50
  • 1
    A lot has changed in the last 5 years... :) – Aaron Gibralter Jun 03 '16 at 21:26
  • today, with Chrome (Chromium 51 on linux): with cookies set with domain B, then try to read from an iframe (domain B) within parent page (domain A) : impossible*. localStorage() with script in iframe (domain B) : impossible*, you have an "acced denied" error message. * means impossible except if user doesn't uncheck "Block third party..." in settings/content. if you uncheck both work but don't count on users to uncheck... – comte Aug 22 '16 at 15:05
  • 3
    So is there a way to set 3rd party cookie today, when it is set in browser to block 3rd party cookie? Or is can someone verify that it is not possible today in any way? – naviram Jul 14 '17 at 16:33
  • 1
    @naviram It is not possible, as that is exactly what the relevant browser setting is for. If it *was* possible, that would be a security bug in the affected browsers and would certainly be fixed soon after. – caw Sep 03 '18 at 15:05
  • 1
    @caw it certainly _was_ possible as I used that loophole for an embeddable polling application from 2009-2013, and it worked in _all_ browsers with default settings. It was not treated as a security bug for some reason as it was left open for a very, very long time. – Aaron Gibralter Sep 04 '18 at 01:27
  • 1
    @AaronGibralter I definitely don’t doubt that. But browsers’ security policies do change, and 5-9 years is a long time in the development of web browsers. Today, if you opt to block third-party cookies, that usually works reliably. – caw Sep 04 '18 at 01:43
  • @caw true true. – Aaron Gibralter Sep 04 '18 at 10:56
  • 5
    lol, these comments actually do explain a lot about the evolution of web browser cookies over time ... – hsuk Oct 09 '19 at 22:10
  • I'm trying to see how facebook cookies httponly are been set today but when debugging the network request I can see some request but there is not set-cookie on the headers, any idea how this is happening? @AaronGibralter – diegoddox Mar 28 '20 at 09:48
  • Honestly, I haven't looked at how this works with modern browsers... – Aaron Gibralter Mar 28 '20 at 19:44
  • 2
    Third-party cookies will be phased out totally in the next 1.5 - 2 years, at least in Chrome, Safari, and most probably Firefox. They were already phased out on the newest versions of Safari and from the incognito mode of Chrome. Users can also turn them off. The current workaround for the browsers where it still works is to check if cookies are saveable from an iframe and if not - shortly open iframe domain in main window (redirect to url and back by JS). Then with proper parameter SameSite (for example SameSite=None) in the cookie they work, but only in those browsers. – Zbyszek Aug 22 '20 at 09:46
  • Sounds like me trying to figure out how to pass microsoft's b2c session cookie across subdomains via iframe is a solution that's very limited now. – Luminous Oct 22 '21 at 01:31
  • I have recently posted a [related answer](https://stackoverflow.com/a/73599289/17865804) for anyone who would be interested in having a look. – Chris Sep 07 '22 at 13:21