簡體   English   中英

Safari 3rd party cookie iframe 技巧不再有效?

[英]Safari 3rd party cookie iframe trick no longer working?

所以這是“我如何讓 3rd 方 cookie 在 Safari 中工作”問題的第十次報復,但我再次問,因為我認為競爭環境已經改變,也許在 2012 年 2 月之后。獲得 3rd 的標准技巧之一Safari 中的派對 cookie 如下:使用一些 javascript 發布到隱藏的 iframe。 它(曾經)欺騙 Safari 認為用戶已經與第 3 方內容進行了交互,然后允許設置 cookie。

認為這個漏洞已經在輕微的丑聞之后被關閉了,因為它被揭露谷歌在其廣告中使用了這個技巧。 至少,在使用這個技巧時,我完全無法在 Safari 中設置 cookie。 我發現了一些隨機的互聯網帖子,聲稱 Apple 正在努力彌補漏洞,但我沒有找到任何官方消息。

作為后備,我什至嘗試重新設計主要的第三方框架,以便您必須在加載內容之前單擊一個按鈕,但即使是這種級別的直接交互也不足以融化 Safari 冰冷的心。

那么有沒有人確定Safari是否確實關閉了這個漏洞? 如果是這樣,是否有其他解決方法(除了在每個請求中手動包含會話 ID)?

只是想在這里留下一個不需要用戶交互的簡單工作解決方案。

正如我在一篇文章中所述:

基本上您需要做的就是在 top.location 上加載您的頁面,創建會話並將其重定向回 Facebook。

將此代碼添加到index.php的頂部並將$page_url設置$page_url您的應用程序最終選項卡/應用程序 URL,您將看到您的應用程序將正常運行。

<?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
?>

注意:這是為 facebook 制作的,但它實際上可以在任何其他類似情況下工作。


2012 年 12 月 20 日編輯 - 維護簽名請求:

上面的代碼不維護請求發布數據,並且您將丟失簽名請求,如果您的應用程序依賴簽名請求,請隨意嘗試以下代碼:

注意:這仍在正確測試中,可能不如第一個版本穩定。 使用風險自負/感謝反饋。

(感謝CBroe在這里為我指明了正確的方向,以改進解決方案)

// 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

你說你願意讓你的用戶在內容加載之前點擊一個按鈕。 我的解決方案是讓一個按鈕打開一個新的瀏覽器窗口。 該窗口為我的域設置了一個 cookie,刷新了打開程序,然后關閉。

所以你的主腳本可能看起來像:

<?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 ?>

然后 safari_cookie_fix.php 看起來像:

<?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>

我用 .htaccess 欺騙了 Safari:

#http://www.w3.org/P3P/validator.html
<IfModule mod_headers.c>
Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID CUR ADM DEV OUR BUS\""
Header set Set-Cookie "test_cookie=1"
</IfModule>

它也停止為我工作。 我所有的應用程序都在 Safari 中丟失了會話,並且正在重定向出 Facebook。 由於我急於修復這些應用程序,我目前正在尋找解決方案。 我會及時向大家發布。

編輯(2012-04-06):顯然蘋果用 5.1.4“修復”了它。 我確定這是對 Google 事物的反應:“執行其 cookie 策略時存在問題。如果 Safari 中的“阻止 Cookie”首選項設置為默認設置,第三方網站可以設置 cookie來自第三方和廣告商” 。http://support.apple.com/kb/HT5190

對於我的具體情況,我通過使用 window.postMessage() 並消除任何用戶交互來解決該問題。 請注意,這僅在您可以以某種方式在父窗口中執行 js 時才有效。 通過讓它包含來自您的域的 js,或者如果您可以直接訪問源代碼。

在 iframe (domain-b) 中,我檢查是否存在 cookie,如果未設置,則會向父級 (domain-a) 發送 postMessage。 例如;

if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1
    && document.cookie.indexOf("safari_cookie_fix") < 0) {
    window.parent.postMessage(JSON.stringify({ event: "safariCookieFix", data: {} }));
}

然后在父窗口(域-a)中監聽事件。

if (typeof window.addEventListener !== "undefined") {
    window.addEventListener("message", messageReceived, false);
}

function messageReceived (e) {
    var data;

    if (e.origin !== "http://www.domain-b.com") {
        return;
    }

    try {
        data = JSON.parse(e.data);
    }
    catch (err) {
        return;
    }

    if (typeof data !== "object" || typeof data.event !== "string" || typeof data.data === "undefined") {
        return;
    }

    if (data.event === "safariCookieFix") {
        window.location.href = e.origin + "/safari/cookiefix"; // Or whatever your url is
        return;
    }
}

最后在您的服務器 (http://www.domain-b.com/safari/cookiefix) 上設置 cookie 並重定向回用戶來自的位置。 下面的例子是使用 ASP.NET MVC

public class SafariController : Controller
{
    [HttpGet]
    public ActionResult CookieFix()
    {
        Response.Cookies.Add(new HttpCookie("safari_cookie_fix", "1"));

        return Redirect(Request.UrlReferrer != null ? Request.UrlReferrer.OriginalString : "http://www.domain-a.com/");
    }

}

在您的 Ruby on Rails 控制器中,您可以使用:

private

before_filter :safari_cookie_fix

def safari_cookie_fix
  user_agent = UserAgent.parse(request.user_agent) # Uses useragent gem!
  if user_agent.browser == 'Safari' # we apply the fix..
    return if session[:safari_cookie_fixed] # it is already fixed.. continue
    if params[:safari_cookie_fix].present? # we should be top window and able to set cookies.. so fix the issue :)
      session[:safari_cookie_fixed] = true
      redirect_to params[:return_to]
    else
      # Redirect the top frame to your server..
      render :text => "<script>alert('start redirect');top.window.location='?safari_cookie_fix=true&return_to=#{set_your_return_url}';</script>"
    end
  end
end

我遇到了同樣的問題,今天我找到了一個適合我的修復程序。 如果用戶代理包含Safari並且沒有設置 cookie,我會將用戶重定向到 OAuth 對話框:

<?php if ( ! count($_COOKIE) > 0 && strpos($_SERVER['HTTP_USER_AGENT'], 'Safari')) { ?>
<script type="text/javascript">
    window.top.location.href = 'https://www.facebook.com/dialog/oauth/?client_id=APP_ID&redirect_uri=MY_TAB_URL&scope=SCOPE';
</script>
<?php } ?>

在身份驗證和請求權限后,OAuth 對話框將重定向到頂部位置的我的 URI。 所以設置cookies是可能的。 對於我們所有的畫布和頁面選項卡應用程序,我已經包含了以下腳本:

<script type="text/javascript">
    if (top.location.href==location.href) top.location.href = 'MY_TAB_URL';
</script>

因此,用戶將再次重定向到已設置有效 cookie的 Facebook 頁面選項卡,並再次發布簽名請求。

我終於找到了與 Sascha 提供的解決方案類似的解決方案,但稍作調整,因為我在 PHP 中明確設置了 cookie:

// excecute this code if user has not authorized the application yet
// $facebook object must have been created before

$accessToken = $_COOKIE['access_token']

if ( empty($accessToken) && strpos($_SERVER['HTTP_USER_AGENT'], 'Safari') ) {

    $accessToken = $facebook->getAccessToken();
    $redirectUri = 'https://URL_WHERE_APP_IS_LOCATED?access_token=' . $accessToken;

} else {

    $redirectUri = 'https://apps.facebook.com/APP_NAMESPACE/';

}

// generate link to auth dialog
$linkToOauthDialog = $facebook->getLoginUrl(
    array(
        'scope'         =>  SCOPE_PARAMS,
        'redirect_uri'  =>  $redirectUri
    )
);

echo '<script>window.top.location.href="' . $linkToOauthDialog . '";</script>';

這樣做是在瀏覽器是 safari 時檢查 cookie 是否可用。 在下一步中,我們在應用程序域上,即上面作為 URL_WHERE_APP_IS_LOCATED 提供的 URI。

if (isset($_GET['accessToken'])) {

    // cookie has a lifetime of only 10 seconds, so that after
    // authorization it will disappear
    setcookie("access_token", $_GET['accessToken'], 10); 

} else {

  // depending on your application specific requirements
  // redirect, call or execute authorization code again
  // with the cookie now set, this should return FB Graph results

}

因此,在重定向到應用程序域后,顯式設置了 cookie,並將用戶重定向到授權過程。

在我的情況下(因為我使用的是 CakePHP,但它應該可以與任何其他 MVC 框架一起正常工作)我再次調用登錄操作,其中再次執行 FB 授權,這次由於現有 cookie 成功。

對應用程序進行一次授權后,我在 Safari (5.1.6) 上使用該應用程序沒有任何問題

希望這可以幫助任何人。

我在運行 iOS 的設備上遇到了這個問題。 我使用 iframe 制作了一個可嵌入普通網站的商店。 不知何故,在每次頁面加載時,用戶都會獲得一個新的 sessionid,導致用戶在進程中途卡住,因為會話中不存在某些值。

我嘗試了此頁面上給出的一些解決方案,但彈出窗口在 iPad 上效果不佳,我需要最透明的解決方案。

我使用重定向解決了它。 嵌入我的網站的網站必須首先將用戶重定向到我的網站,因此頂部框架包含我網站的 url,我在其中設置了一個 cookie 並將用戶重定向到嵌入我的網站的網站上的正確頁面,該頁面被傳遞通過網址。

示例 PHP 代碼

遠程網站將用戶重定向到

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

初始化文件

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

用戶最終會http://www.domain.com/shop/frame我的網站嵌入的http://www.domain.com/shop/frame ,按原樣存儲會話並食用 cookie。

希望這可以幫助某人。

讓我分享我在 ASP.NET MVC 4 中的修復。主要思想就像 PHP 的正確答案。 在腳本部分附近的標題中的主布局中添加的下一個代碼:

@if (Request.Browser.Browser=="Safari")
{
    string pageUrl = Request.Url.GetLeftPart(UriPartial.Path);
    if (Request.Params["safarifix"] != null && Request.Params["safarifix"] == "doSafariFix")
    {
        Session["IsActiveSession"] = true;
        Response.Redirect(pageUrl);
        Response.End();
    }
        else if(Session["IsActiveSession"]==null)
    {
        <script>top.window.location = "?safarifix=doSafariFix";</script>
    }
}

此解決方案適用於某些情況 - 如果可能:

如果 iframe 內容頁面使用包含 iframe 的頁面的子域,則不再阻止 cookie。

谷歌實際上在這個問題上放過了貓。 他們使用它來訪問跟蹤 cookie 有一段時間了。 Apple 幾乎立即修復了它 =\\

華爾街日報帖子

這是我使用的一些代碼。 我發現,如果我從我的網站設置任何 cookie,那么 cookie 從那時起就會在 iframe 中神奇地工作。

http://developsocialapps.com/foundations-of-a-facebook-app-framework/

 if (isset($_GET['setdefaultcookie'])) {
        // top level page, set default cookie then redirect back to canvas page
        setcookie ('default',"1",0,"/");
        $url = substr($_SERVER['REQUEST_URI'],strrpos($_SERVER['REQUEST_URI'],"/")+1);
        $url = str_replace("setdefaultcookie","defaultcookieset",$url);
        $url = $facebookapp->getCanvasUrl($url);
        echo "<html>\n<body>\n<script>\ntop.location.href='".$url."';\n</script></body></html>";
        exit();
    } else if ((!isset($_COOKIE['default'])) && (!isset($_GET['defaultcookieset']))) {
        // no default cookie, so we need to redirect to top level and set
        $url = $_SERVER['REQUEST_URI'];
        if (strpos($url,"?") === false) $url .= "?";
        else $url .= "&";
        $url .= "setdefaultcookie=1";
        echo "<html>\n<body>\n<script>\ntop.location.href='".$url."';\n</script></body></html>";
        exit();
    }

一個稍微簡單的 PHP 版本,與其他人發布的內容相比:

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();
}

我找到了完美的答案,這一切都歸功於一個叫艾倫的人,他在這里值得所有的榮譽。 ( http://www.allannienhuis.com/archives/2013/11/03/blocked-3rd-party-session-cookies-in-iframes/ )

他的解決方案簡單易懂。

在 iframe 內容服務器(域 2)上,在根域級別添加一個名為startsession.php的文件,其中包含:

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

現在在包含 iframe (domain1) 的頂級網站上,對包含 iframe 的頁面的調用應如下所示:

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

就是這樣! 簡單:)

這樣做的原因是因為您將瀏覽器定向到第三方 URL,因此在 iframe 中顯示來自它的內容之前告訴它信任它。

我使用了修改過的(在鏈接中添加了 signed_request 參數)Whiteagle 的技巧,它在 safari 中運行良好,但在這種情況下,IE 會不斷刷新頁面。 所以我對 safari 和 Internet Explorer 的解決方案是:

$fbapplink = 'https://apps.facebook.com/[appnamespace]/';
$isms = stripos($_SERVER['HTTP_USER_AGENT'], 'msie') !== false;

// safari fix
if(! $isms  && !isset($_SESSION['signed_request'])) {

    if (isset($_GET["start_session"])) {
        $_SESSION['signed_request'] = $_GET['signed_request'];
        die(header("Location:" . $fbapplink ));

    }
    if (!isset($_GET["sid"])) {
        die(header("Location:?sid=" . session_id() . '&signed_request='.$_REQUEST['signed_request']));
    }
    $sid = session_id();
    if (empty($sid) || $_GET["sid"] != $sid) {
    ?>
    <script>
        top.window.location="?start_session=true";
    </script>
    <?php
    exit;
    }
}

// IE fix
header('P3P: CP="CAO PSA OUR"');
header('P3P: CP="HONK"');


.. later in the code

$sr = $_REQUEST['signed_request'];
if($sr) {
        $_SESSION['signed_request'] = $sr;
} else {
        $sr = $_SESSION['signed_request'];
}

我也一直遇到這個問題,但最終得到了解決方案,最初直接在瀏覽器中加載 iframe url 就像小彈出窗口一樣,然后只訪問 iframe 內的會話值。

Safari 現在會阻止所有第三方 cookie。 您只能使用 Storage API 來嘗試讓用戶訪問其第三方 cookie。

https://www.infoq.com/news/2020/04/safari-third-party-cookies-block/

我在現有答案中沒有清楚說明的一些上下文(自 2012 年以來也發生了很多變化!):

如果您可以同時控制第 3 方 iframe 和父頁面(即您可以在父頁面上插入 JavaScript),那么有幾種解決方法可用。 我建議其中最優雅的方法是使用 @Frank 的回答所描述的 postMessage API,因為 a) 這不需要任何重定向,b) 不需要任何用戶交互。

如果您不控制第 3 方 iframe 和父頁面,例如您在不受控制的網站上托管了一個小部件,那么截至 2020 年 5 月,此處發布的大多數答案在Safari中將不起作用,並且將停止工作2022 年左右在 Chrome 中 也就是說,除非用戶已經訪問了您的域或與 iframe 交互,否則您無法設置 cookie。 但是,有一些商業服務提供了解決此問題的解決方案,例如CloudCookie.io

我最近在 Safari 上遇到了同樣的問題。 我想出的解決方案是基於本地存儲 HTML5 API。 使用本地存儲,您可以模擬 cookie。

這是我的詳細博客文章: http : //log.scalemotion.com/2012/10/how-to-trick-safari-and-set-3rd-party.html

我決定一起擺脫$_SESSION變量並在 memcache 周圍編寫一個包裝器來模擬會話。

檢查https://github.com/manpreetssethi/utils/blob/master/Session_manager.php

用例:在用戶登陸應用程序的那一刻,使用 Session_manager 存儲已簽名的請求,因為它在緩存中,您以后可以在任何頁面上訪問它。

注意:這在 Safari 中進行私密瀏覽時不起作用,因為每次頁面重新加載時 session_id 都會重置。 (愚蠢的野生動物園)

您可以通過將標頭添加為 p3p 策略來解決此問題。我在 safari 上遇到了同樣的問題,因此在文件頂部添加標頭后解決了我的問題。

<?php
header('P3P:CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"');
?>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM