Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safari 13+ iframe blocks CORS cookies

Tags:

Safari flat out doesn't let you set cookies in iframes of domains different than the parent domain, server-side CORS headers be damned.

To clarify: user is on domainA.com. An iframe for domainB.com is open, and attempts to authenticate the user on domainB.com inside the iframe. Set-Cookie header is returned from the server inside the domainB.com iframe, with all the required headers, but Safari isn't sending it back in subsequent calls.

An old workaround was doing a form submit from the iframe, and set the cookie in the response. I guess they liked the fact that the user was clicking something to submit the form. You'd have to poll for the cookie to see when the response came back, as form submits have no callbacks, and in the case of HttpOnly cookies you couldn't, but hey, it worked! Until it didn't.

Then, a more recent workaround was redirecting the user to the iframe domain in a brand new window/tab, setting a random cookie there, and from that moment on, that subdomain was "trusted" inside the iframe. Again, it required a click to open the new window/tab, and there was even a visual indication of the new tab opening. Much security, such standards.

And now, as of Safari 13 - No more workaround. No more secure iframe cookie setting 🤬

Any other authentication scheme isn't good for us (e.g. Auth-X header). We need to use an HttpOnly secure cookie, as we don't want that token to be in any way accessible by javascript client-side.

To be clear, everything works great on any other browser.

Relevant WebKit Bugzilla

Does anyone have any suggestions?

Edit:

Thanks for the link @tomschmidt, that seems like the right direction. I tried using Apple's Storage Access API, but unfortunately, although I'm making sure to request access before initializing my login logic with the API:

requestStorageAccess = async() => {     return new Promise(resolve => {       //@ts-ignore       document.requestStorageAccess().then(         function () {           console.log('Storage access was granted');           resolve(true);         },         function () {           console.log('Storage access was denied');           resolve(false);         }       );         });   }   const storageAccessGranted = await requestStorageAccess(); console.log(storageAccessGranted) // prints 'true' await login(); 

Still, the cookies received on the /login API response are not getting sent in subsequent calls to the API :(

Edit 2 (May 2021):

Safari 14 has added another breaking change:

https://webkit.org/blog/11545/updates-to-the-storage-access-api/

Go Apple go! You're making us reminisce about IE6.

like image 330
Tom Teman Avatar asked Jan 13 '20 19:01

Tom Teman


People also ask

Does Safari block iframe?

Safari blocks cookies for iFrame domain when domain doesn't match source website #18530.

Can iframe access parent cookies?

You can only read the cookie of the iframe within the same iframe only and after reading you can pass the cookie value to the parent window using the postMessage.

Why iframe is not working in Safari?

Safari will not allow a web app displayed in an iframe to set/store cookies -> Safari rejects it with "bad csrf" token. I was able to make it work with a change of preferences in Safari. In Safari's Preferences, select Privacy tab, and disable "Prevent cross-site tracking".

How do I enable cross domain cookies in Safari?

Open the Safari browser. From the menu bar, go to Safari > Preferences. In the preferences dialog, go to the Privacy tab and disable the Prevent cross-site tracking permission.


1 Answers

I think I might have found the solution: Apple's Storage Access API: https://webkit.org/blog/8124/introducing-storage-access-api/

like image 118
tomschmidt Avatar answered Sep 22 '22 07:09

tomschmidt