Skip to content

Instantly share code, notes, and snippets.

@iansltx
Last active July 30, 2024 14:53
Show Gist options
  • Save iansltx/18caf551baaa60b79206 to your computer and use it in GitHub Desktop.
Save iansltx/18caf551baaa60b79206 to your computer and use it in GitHub Desktop.
Safari iframe cookie workaround
<?php
header("Location: " . $_GET['redirect']);
setcookie("__trust");
<?php
if (!isset($_COOKIE['testcookie']))
echo "Cookie not set!";
else if ($_COOKIE['testcookie'] != $_GET['cookie'])
echo "Cookies don't match: " . $_COOKIE['testcookie'] . ' != ' . $_GET['cookie'];
else
echo "Cookies match!";
<?php
$value = uniqid();
setcookie("testcookie", $value);
echo "<p>Now go <a href='dest_get.php?cookie=" . $value . "'>here</a></p>";
<?php
$internalPath = "http://local.test/path";
$externalPath = "http://remote.test/path";
?>
<html><head><title>Redirect Cookie Test</title></head>
<body>
<?php if ($_GET['redirected']): ?>
<p>iframe starts below...</p>
<iframe src="<?= $externalPath ?>/dest_set.php"?>
<?php else: ?>
<a href="<?= $externalPath ?>/dest_bounce.php?redirect=<?= $internalPath ?>/src.php?redirected=true">Bounce here...</a>
<?php endif; ?>
</body>
@WebSpectrum
Copy link

Hi All - what is the best solution to date if you don't have control or ability to deploy code on site B ? ....

@xk4r00t
Copy link

xk4r00t commented Mar 16, 2020

I used a popup to do the trick (by temporary passing the cookie as parameter to a third party API).
If you have full control on site B (code + DNS) I advice you to declare a subdomain in you site B which forward silently to your wished website/API (add a new AAAA entry with your service IP) :

       +------------------+                          +-----------------------+
       |                  |   XHR with credentials   |                       |
       |  www.siteB.com   --------------------------->  api-siteA.siteB.com  |
       |                  |                          |                       |
       +------------------+                          +-----------------------+

@russau
Copy link

russau commented Mar 31, 2020

@mwleinad
Copy link

mwleinad commented Apr 7, 2020

Any idea if there's a workaround with safari 13.1?

@antstorm
Copy link

Looks like requesting storage access via their APIs is the way to do it — https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/

@Arcolye
Copy link

Arcolye commented Apr 29, 2020

What a fantastic time to put this extra hurdle on struggling and furloughed development teams. Thanks Apple, Safari, and specifically John Wilander!

With brick-and-mortar businesses struggling and software companies doing what they can to help out, NOW was the time to release this huge software-breaking change? Not 2022 like Chrome has roadmapped? Now? During the Covid recession? And with "Storage Access API" still in a poorly-documented and experimental phase? Now?

Badly done, Safari. Badly done indeed. Shame on you, John Wilander.

@asecondwill
Copy link

The workarounds seem to work, but not in webkit view in eg facebook/twitter/instagram webviewer. And clues on what to do would be ace.

@stevenlawrance
Copy link

From https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/, it appears that a workaround that uses OAuth2 may exist, though it's not exactly clear how to invoke this (and using Secure+HttpOnly cookies isn't sufficient to make it work). I'll have to poke around the WebKit source code..

Option 1: OAuth 2.0 Authorization with which the authenticating domain (in your case, the third-party that expects cookies) forwards an authorization token to your website which you consume and use to establish a first-party login session with a server-set Secure and HttpOnly cookie.

@github-xuser
Copy link

I have a workaround based on an interface to sagepay.
We tell sagepay where to return to after CC entry in an iframe, Once the user submits the CC form to sagepay, they redirect the iframe to us and we take over control of the iframe and close it.
Unless its the latest safari. Then the iframe redirect happens, but with no session cookie so our software has no continuity and terminates because it thinks the session has timedout. Not very good when someone is trying to buy something in your shop.
I already implemented a change so that the iframe was created with a page from our domain which then redirects to sagepay, so i know that safari has the correct session cookie in the iframe. This did actually fix quite a lot of the problems but not all.
My thought for fixing them all was that safari doesnt like sending the correct session cookie when sagepay redirects back to our domain, but i wonder what will happen if i make the redirect from sagepay simply do another redirect from us, to us.
It worked, on the second redirect from our domain to our domain the session cookie is correct.
That has to be a bug in safari.
So if i am dom1.com and sagepay is dom2.com the fix is:
Create an iframe with src = dom1.com/redirect1 this simply contains html or javascript to do the correct redirect to your dom2.com page.
Tell dom2.com to return to dom1.com/dummyredirect. dummyredirect copies all the querystring or post data and returns a page that redirects back to dom1.com/theproperreturnaddress.
Its passed all our tests so far.
I hope it helps someone else, I can't see safari getting fixed or even acknowledging the bug anytime soon.

@xabier98
Copy link

Hi

Please ¿can you explain or write an small example with your solution?

Thank you

Best Regards

@engelmav
Copy link

What a fantastic time to put this extra hurdle on struggling and furloughed development teams. Thanks Apple, Safari, and specifically John Wilander!

With brick-and-mortar businesses struggling and software companies doing what they can to help out, NOW was the time to release this huge software-breaking change? Not 2022 like Chrome has roadmapped? Now? During the Covid recession? And with "Storage Access API" still in a poorly-documented and experimental phase? Now?

Badly done, Safari. Badly done indeed. Shame on you, John Wilander.

Fascinating. The economic impact of code changes... should be factored in with behemoth applications and firms like Safari/Apple.

@jhud
Copy link

jhud commented May 30, 2020

Hi everyone, commiserations to those of you who also got blindsided by this during all the other Covid-19 IT dramas. Anyway, here is my quick fix for this.

Note that you cannot nest the document.hasStorageAccess, otherwise it misses the user interaction, so I don't bother checking - I run the code every time. I dropped this code inside my iframe. It needs to be triggered from an onClick, ie:

 <div onclick="safariFix();">If you have problems logging in on Safari, please click here.</div>

But instead I call this directly from my login form:

  <input type="submit" onclick="safariFix();" id="login_submit_button" value="{% trans 'Log in' %}" />

The first login fails because Safari pops up a non-blocking "do you want to allow..." popup, but it'll suffice until there's a fix that won't pollute the UI with some "click this if you are on Safari" button.

<script>
  // Safari now suddenly blocks iframe cookie access, so we need to call this during some user interaction
  function safariFix() {
    if (navigator.userAgent.search("Safari") >= 0 && navigator.userAgent.search("Chrome") < 0) {
      document.requestStorageAccess().then(() => {
          // Now we have first-party storage access!
          console.log("Got cookie access for Safari workaround");
          // Let's access some items from the first-party cookie jar
          document.cookie = "foo=bar";              // drop a test cookie
        },  () => { console.log('access denied') }).catch((error) => {
          // error obtaining storage access.
          console.log("Could not get access for Safari workaround: " + error);
        });
      }
  }
</script>

Apologies for the messiness - it's Saturday night and I just need to rush this out now so my customers can start making money again.

@mpirog-hw
Copy link

mpirog-hw commented Jun 5, 2020

The economic impact of code changes... should be factored in with behemoth applications and firms like Safari/Apple.

Not just economic, but very real health impact. My company delivers healthcare related information to patients, including COVID-19 content. We act as a third party to health plans and it's an all too common practice for this industry to integrate within iframes.

As it stands, patients using Safari can't access our content due to this security change. Content like ours has been shown to improve health outcomes. If you use Safari you might suffer a worse outcome in the event of a health crisis.

looks like requesting storage access via their APIs is the way to do it

The storage access API in Safari will flat out reject requestStorageAccess() if the client hasn't visited the third-party in first-party context AND has interacted with the site — https://stackoverflow.com/questions/52173595/how-to-debug-safari-itp-2-0-requeststorageaccess-failure

Interestingly, Firefox's implementation doesn't appear to enforce this same requirement, only adding to the confusion.

The majority of our users don't know who we are and have never visited our domain directly. The Storage Access API is clearly designed to accommodate social media network workflows. The rest of us are getting steamrolled.

@lenusch
Copy link

lenusch commented Jul 5, 2020

Does it work now? Is there a functional workarround? I didn't get this to work until now :-(

@sarayaz
Copy link

sarayaz commented Jul 8, 2020

Does anybody have solution for this in safari 13+ ?

@joostfaassen
Copy link

None of these solutions worked for us. And the same issue started showing up in Google Chrome and other browsers (especially in incognito / private modes).

What we did is add an upstream location on the vhost of the site that embeds the other site. I.e. this adds https://mainsite/my-embedded-site/* that forwards requests to https://my-embedded-site/

This way both sites get served to the end user from the main domain (mainsite) making all cookies "first party" cookies.

This solves the problem for us on all combinations of platforms, browsers and incognito vs normal modes.

Additionally, make sure your "secure" and "samesite" cookie options are set correctly, and make sure the cookie names on the main + embedded sites differ (otherwise they keep thrashing eachother's sessions 😄 )

It does require that you control the embedding app's server, so this won't solve the situation for everybody.. but I hope it'll help some people in this thread!

@jhud
Copy link

jhud commented Aug 18, 2020

Note that Apple seems to keep closing off iFrame cookies with every Safari update and breaking my workarounds. I gave up and am moving to a JS library. It might be possible to pass cookies with postMessage, but in the end it'll be less screwing around to just do an API integration with the host sites.

@luxio
Copy link

luxio commented Aug 20, 2020

@joostfaassen Thank you for sharing your solution.

What we did is add an upstream location on the vhost of the site that embeds the other site. I.e. this adds https://mainsite/my-embedded-site/* that forwards requests to https://my-embedded-site/

Could you share your server configuration to create the upstream location?

@JamesMcMurrin
Copy link

I tried a similar script to this, and IE 11 died just from having the document.requestStorageAccess in the script. Never mind that it'll never reach it (or that I put it in a try catch), it throws a syntax error just seeing it.

The first login fails because Safari pops up a non-blocking "do you want to allow..." popup, but it'll suffice until there's a fix that won't pollute the UI with some "click this if you are on Safari" button.

<script>
  // Safari now suddenly blocks iframe cookie access, so we need to call this during some user interaction
  function safariFix() {
    if (navigator.userAgent.search("Safari") >= 0 && navigator.userAgent.search("Chrome") < 0) {
      document.requestStorageAccess().then(() => {
          // Now we have first-party storage access!
          console.log("Got cookie access for Safari workaround");
          // Let's access some items from the first-party cookie jar
          document.cookie = "foo=bar";              // drop a test cookie
        },  () => { console.log('access denied') }).catch((error) => {
          // error obtaining storage access.
          console.log("Could not get access for Safari workaround: " + error);
        });
      }
  }
</script>

@benross
Copy link

benross commented Sep 9, 2020

Thanks for the many ideas in this thread!

Wanted to share we've been using a service to get around this issue and so far it has been working well for us: cloudcookie.io. We host content in 3rd party iframes and often don't have access to the parent (host) page. It's a commercial solution so might not be appropriate for all but pretty inexpensive (and has a free tier).

@lenusch
Copy link

lenusch commented Sep 10, 2020

Thanks for the many ideas in this thread!

Wanted to share we've been using a service to get around this issue and so far it has been working well for us: cloudcookie.io. We host content in 3rd party iframes and often don't have access to the parent (host) page. It's a commercial solution so might not be appropriate for all but pretty inexpensive (and has a free tier).

Hi, i double checked everything but we have a PHP App and need a Session Cookie and this Javascript "CloudCookie" will not be able to pass Session Cookie to PHP, or am i mistaken? My Mate told me this would be not fit my needs. :-S

@jhud
Copy link

jhud commented Sep 10, 2020

I looked at some existing solutions, and big companies which rely on iframes appear to be passing the session tokens through PostMessage between the host page and the iframe.

But I am sick of doing these increasingly ugly hacks. IMO, iframes and 3rd party cookies are dead - Apple has just killed them a year or so earlier.

So I have converted my old iframe integrations to use my existing app REST API + JavaScript + local storage. My customers love this JS client-side integration compared to iframes, and it gives me a unified interface for my apps and web. It's a much more solid solution which will last for the ages.

I know you don't want to hear this if you are looking for a quick fix, but I suggest that you already start planning to ditch iframes + 3rd party cookies in the medium to long term.

@code2infiniteE
Copy link

Thanks for the many ideas in this thread!
Wanted to share we've been using a service to get around this issue and so far it has been working well for us: cloudcookie.io. We host content in 3rd party iframes and often don't have access to the parent (host) page. It's a commercial solution so might not be appropriate for all but pretty inexpensive (and has a free tier).

Hi, i double checked everything but we have a PHP App and need a Session Cookie and this Javascript "CloudCookie" will not be able to pass Session Cookie to PHP, or am i mistaken? My Mate told me this would be not fit my needs. :-S

I also tried cloudcookie.io and have it working on a project. It's a front-end (javascript) cookie framework, so if you need the cookies on the server-side (eg PHP), you just need to add an ajax call or page redirect once you get the cookies from the front-end. (@lenusch)

@Benamin
Copy link

Benamin commented Sep 17, 2020

@sparkdoo
Copy link

So I have converted my old iframe integrations to use my existing app REST API + JavaScript + local storage. My customers love this JS client-side integration compared to iframes, and it gives me a unified interface for my apps and web. It's a much more solid solution which will last for the ages.

@jhud how are you dealing with the security implications of providing a client side javascript approach vs iframe? We considered both options but found the risk of running our javascript next to potentially malicious javascript too much of a concern to proceed, but of course as you say the new concern is that our existing solution will be completely blocked in the not so distant future

@Tofandel
Copy link

The joys of tech giants imposing their wishes to everybody because they are trying to block third party tracking, except third party tracking can find tons of workaround other than cookies usually, but for authenticating a user in a secure way you need cookies, so effectively they screw you, force you to use a thousand times less secure approach for the sake of user privacy and don't give you an alternative

Iframes are not just used for third party tracking and sadly they don't understand that.

@jhud
Copy link

jhud commented Aug 31, 2021

So I have converted my old iframe integrations to use my existing app REST API + JavaScript + local storage. My customers love this JS client-side integration compared to iframes, and it gives me a unified interface for my apps and web. It's a much more solid solution which will last for the ages.

@jhud how are you dealing with the security implications of providing a client side javascript approach vs iframe? We considered both options but found the risk of running our javascript next to potentially malicious javascript too much of a concern to proceed, but of course as you say the new concern is that our existing solution will be completely blocked in the not so distant future

I trust all the host websites. I would love to have better integration to avoid CSRF/XSS attacks, but it is sufficient for my customers' purposes, and it is the situation the tech vendors have left us in.

The approach is basically to write a Single Page Application. After having done React and Vue.js development since making this decision, it has just cemented my opinion that client-side JS is the way to go for anything other than a basic CRUD website.

@gbenchanoch
Copy link

Thanks for the many ideas in this thread!

Wanted to share we've been using a service to get around this issue and so far it has been working well for us: cloudcookie.io. We host content in 3rd party iframes and often don't have access to the parent (host) page. It's a commercial solution so might not be appropriate for all but pretty inexpensive (and has a free tier).

Are you still using CloudCookie? Has the solution been stable for you across all browsers, as well as mobile? I am having stability issues loading a specific 3rd party provider via iframe, particularly on Safari.

@pini85
Copy link

pini85 commented Oct 14, 2021

Thanks for the many ideas in this thread!

Wanted to share we've been using a service to get around this issue and so far it has been working well for us: cloudcookie.io. We host content in 3rd party iframes and often don't have access to the parent (host) page. It's a commercial solution so might not be appropriate for all but pretty inexpensive (and has a free tier).

I would also be interested to know if this is still valid

@code2infiniteE
Copy link

@pini85 && @gbenchanoch yes cloudcookie.io has been working for us so far! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment