问题
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 :(
回答1:
I think I might have found the solution: Apple's Storage Access API: https://webkit.org/blog/8124/introducing-storage-access-api/
回答2:
So, the workaround still kinda works, as long as the new window is storing the cookie that you want to store. The iframe still can't store it's own cookies. In my case, all I needed was the session id cookie. So, I open a small popup window when the user grants storage access. It gets and stores the session id cookie, closes, and reloads the iframe. The iframe then has access to the session id cookie and sends it in subsequent requests. I think this is just temporary though, it looks like they're going to remove storage access from popup windows sometime in the future. Maybe they'll fix the iframe not being able to store cookies by then.
来源:https://stackoverflow.com/questions/59723056/safari-13-iframe-blocks-cors-cookies