Safari 3rd party cookie iframe trick no longer wor

2019-01-01 06:15发布

So this is the umteenth revenge of the "how do I get 3rd party cookies to work in Safari" question but I'm asking again because I think the playing field has changed, perhaps after February 2012. One of the standard tricks to get 3rd party cookies in Safari was as follows: use some javascript to POST to a hidden iframe. It (used to) trick Safari into thinking that the user had interacted with the 3rd party content and so then allow cookies to be set.

I think this loophole has been closed in the wake of the mild scandal where it was revealed that Google was using that trick with its ads. At the very least, while using this trick I have been completely unable to set cookies in Safari. I unearthed some random internet postings that claimed that Apple was working on closing the loophole but I haven't found any official word.

As a fallback I even tried redesigning the main third party frame so that you had to click on a button before the content would load but even that level of direct interaction was not enough to melt Safari's cold cold heart.

So does anyone know for certain if Safari has indeed closed this loophole? If so, are there other workarounds (other than manually including a session ID in every request)?

19条回答
冷夜・残月
2楼-- · 2019-01-01 06:36

You said you were willing to have your users click a button before the content loads. My solution was to have a button open a new browser window. That window sets a cookie for my domain, refreshes the opener and then closes.

So your main script could look like:

<?php if(count($_COOKIE) > 0): ?>
<!--Main Content Stuff-->
<?php else: ?>
<a href="/safari_cookie_fix.php" target="_blank">Click here to load content</a>
<?php endif ?>

Then safari_cookie_fix.php looks like:

<?php
setcookie("safari_test", "1");
?>
<html>
    <head>
        <title>Safari Fix</title>
        <script type="text/javascript" src="/libraries/prototype.min.js"></script>
    </head>
    <body>
    <script type="text/javascript">
    document.observe('dom:loaded', function(){
        window.opener.location.reload();
        window.close();
    })
    </script>
    This window should close automatically
    </body>
</html>
查看更多
浅入江南
3楼-- · 2019-01-01 06:37

A slightly simper version in PHP of what others have posted:

if (!isset($_COOKIE, $_COOKIE['PHPSESSID'])) {
    print '<script>top.window.location="https://example.com/?start_session=true";</script>';
    exit();
}

if (isset($_GET['start_session'])) {
    header("Location: https://apps.facebook.com/YOUR_APP_ID/");
    exit();
}
查看更多
刘海飞了
4楼-- · 2019-01-01 06:37

I have found the perfect answer to this, all thanks to a guy called Allan that deserves all of the credit here. (http://www.allannienhuis.com/archives/2013/11/03/blocked-3rd-party-session-cookies-in-iframes/)

His solution is simple and easy to understand.

On iframe content server (domain 2), add a file called startsession.php at the root domain level that contains:

<?php
// startsession.php
session_start();
$_SESSION['ensure_session'] = true;
die(header('location: '.$_GET['return']));

Now on the top level website containing the iframe (domain1), the call to the page containing the iframe should look like:

<a href="https://domain2/startsession.php?return=http://domain1/pageWithiFrame.html">page with iFrame</a>

And that's it! Simples :)

The reason this works is because you are directing the browser to a third party URL and thus telling it to trust it before showing content from it within the iframe.

查看更多
临风纵饮
5楼-- · 2019-01-01 06:38

Google actually let the cat out of the bag on this one. They were using it for a while to access tracking cookies. It was fixed almost immediately by Apple =\

original Wall Street Journal post

查看更多
与君花间醉酒
6楼-- · 2019-01-01 06:39

Just wanted to leave a simple working solution here that does not require user interaction.

As I stated in a post I made:

Basically all you need to do is load your page on top.location, create the session and redirect it back to facebook.

Add this code in the top of your index.php and set $page_url to your application final tab/app URL and you’ll see your application will work without any problem.

<?php
    // START SAFARI SESSION FIX
    session_start();
    $page_url = "http://www.facebook.com/pages/.../...?sk=app_...";
    if (isset($_GET["start_session"]))
        die(header("Location:" . $page_url));

    if (!isset($_GET["sid"]))
        die(header("Location:?sid=" . session_id()));
    $sid = session_id();
    if (empty($sid) || $_GET["sid"] != $sid):
?>
   <script>
        top.window.location="?start_session=true";
    </script>
<?php
    endif;
    // END SAFARI SESSION FIX
?>

Note: This was made for facebook, but it would actually work within any other similar situations.


Edit 20-Dec-2012 - Maintaining Signed Request:

The above code does not maintain the requests post data, and you would loose the signed_request, if your application relies on signed request feel free to try the following code:

Note: This is still being tested properly and may be less stable than the first version. Use at your own risk / Feedback is appreciated.

(Thanks to CBroe for pointing me into the right direction here allowing to improve the solution)

// Start Session Fix
session_start();
$page_url = "http://www.facebook.com/pages/.../...?sk=app_...";
if (isset($_GET["start_session"]))
    die(header("Location:" . $page_url));
$sid = session_id();
if (!isset($_GET["sid"]))
{
    if(isset($_POST["signed_request"]))
       $_SESSION["signed_request"] = $_POST["signed_request"];
    die(header("Location:?sid=" . $sid));
}
if (empty($sid) || $_GET["sid"] != $sid)
    die('<script>top.window.location="?start_session=true";</script>');
// End Session Fix
查看更多
回忆,回不去的记忆
7楼-- · 2019-01-01 06:41

I had this problem on devices running iOS. I made a shop that is embeddable in a normal website using an iframe. Somehow, on every pageload the user got a new sessionid, resulting in users getting stuck halfway the process because some values weren't present in the session.

I tried some of the solutions given on this page, but popups don't work very well on an iPad and I needed the most transparent solution.

I resolved it using a redirect. The website that embeds my site must first redirect the user to my site, so the top frame contains the url to my site, where I set a cookie and redirect the user to the proper page on the website that embeds my site, that is passed through in the url.

Example PHP code

Remote website redirects user to

http://clientname.example.com/init.php?redir=http://www.domain.com/shop/frame

init.php

<?php
// set a cookie for a year
setcookie('initialized','1',time() + 3600 * 24 * 365, '/', '.domain.com', false, false);
header('location: ' . $_GET['redir']);
die;

The user ends up on http://www.domain.com/shop/frame where my site is embedded, storing sessions as it should and eating cookies.

Hope this helps someone.

查看更多
登录 后发表回答