it-swarm.com.de

Cookie iframe-Trick von Safari von Drittanbietern funktioniert nicht mehr?

Dies ist also die dreizehnte Rache der Frage "Wie bringe ich Cookies von Drittanbietern dazu, in Safari zu funktionieren", aber ich frage noch einmal, weil ich denke, dass sich die Wettbewerbsbedingungen möglicherweise nach Februar 2012 geändert haben. Einer der Standardtricks, um den dritten Platz zu erreichen In Safari lauteten die Party-Cookies wie folgt: Verwenden Sie JavaScript, um POST= zu einem versteckten Iframe) zu wechseln. Dies hat Safari zu der Annahme verleitet, dass der Benutzer mit Inhalten von Drittanbietern interagiert hat, und lässt dies dann zu zu setzende Cookies.

I think Diese Lücke wurde nach dem milden Skandal geschlossen, als bekannt wurde, dass Google diesen Trick für seine Anzeigen verwendet hat. Zumindest konnte ich mit diesem Trick keine Cookies in Safari setzen. Ich habe einige zufällige Internetpostings entdeckt, die besagten, dass Apple) daran gearbeitet hat, die Lücke zu schließen, aber ich habe kein offizielles Wort gefunden.

Als Fallback habe ich sogar versucht, den Hauptframe eines Drittanbieters so umzugestalten, dass Sie auf eine Schaltfläche klicken mussten, bevor der Inhalt geladen wurde, aber selbst diese direkte Interaktion reichte nicht aus, um Safaris kaltes Herz zum Schmelzen zu bringen.

Weiß also jemand mit Sicherheit, ob Safari diese Lücke tatsächlich geschlossen hat? Wenn ja, gibt es andere Problemumgehungen (außer manuelles Einfügen einer Sitzungs-ID in jede Anforderung)?

132
gs hurley

Ich wollte hier nur eine einfache funktionierende Lösung hinterlassen, die keine Benutzerinteraktion erfordert .

Wie ich in einem Beitrag, den ich gemacht habe :

Grundsätzlich müssen Sie nur Ihre Seite auf top.location laden, die Sitzung erstellen und sie zurück zu Facebook leiten.

Fügen Sie diesen Code oben in Ihr index.php und set $page_url zu der letzten Registerkarte/App-URL Ihrer Anwendung und Sie werden sehen, dass Ihre Anwendung problemlos funktioniert.

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

Hinweis: Diese Funktion wurde für Facebook entwickelt, funktioniert jedoch auch in anderen ähnlichen Situationen.


Edit 20-Dec-2012 - Beibehalten der signierten Anfrage:

Mit dem obigen Code werden die Post-Daten der Anforderungen nicht verwaltet, und Sie würden die Anforderung "signed_request" verlieren, wenn sich Ihre Anwendung auf eine signierte Anforderung stützt. Probieren Sie den folgenden Code aus:

Hinweis: Dies wird noch ordnungsgemäß getestet und ist möglicherweise weniger stabil als die erste Version. Verwendung auf eigene Gefahr/Rückmeldung erwünscht.

(Danke an CBroe , dass Sie mich hier in die richtige Richtung gelenkt haben, um die Lösung zu verbessern.)

// 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
51
Diogo Raminhos

Sie sagten, Sie wären bereit, Ihre Benutzer auf eine Schaltfläche klicken zu lassen, bevor der Inhalt geladen wird. Meine Lösung bestand darin, eine Schaltfläche zum Öffnen eines neuen Browserfensters zu verwenden. Dieses Fenster setzt ein Cookie für meine Domain, aktualisiert den Opener und schließt dann.

So könnte Ihr Hauptskript aussehen:

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

Dann sieht safari_cookie_fix.php so aus:

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

Ich habe Safari mit einem .htaccess ausgetrickst:

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

Und es hat auch für mich aufgehört zu arbeiten. Alle meine Apps verlieren die Sitzung in Safari und werden von Facebook weitergeleitet. Da ich es eilig habe, diese Apps zu reparieren, suche ich derzeit nach einer Lösung. Ich werde euch auf dem Laufenden halten.

Edit (2012-04-06): Anscheinend Apple= "behoben" mit 5.1.4. Ich bin sicher, das ist die Reaktion auf das Google-Ding: "Ein Problem bestand bei der Durchsetzung Auf Websites von Drittanbietern können Cookies gesetzt werden, wenn die Einstellung "Cookies blockieren" in Safari auf die Standardeinstellung "Von Drittanbietern und Werbetreibenden" gesetzt wurde. http://support.Apple.com/ kb/HT519

15
vwoelm

In Ihrem Ruby on Rails Controller können Sie Folgendes verwenden:

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
14
joost

Für meine spezielle Situation habe ich das Problem mithilfe von window.postMessage () gelöst und jegliche Benutzerinteraktion beseitigt. Beachten Sie, dass dies nur funktioniert, wenn Sie js im übergeordneten Fenster ausführen können. Entweder indem Sie ein js aus Ihrer Domain hinzufügen oder wenn Sie direkten Zugriff auf die Quelle haben.

Im iframe (domain-b) überprüfe ich das Vorhandensein eines Cookies und wenn es nicht gesetzt ist, schicke ich eine postMessage an das übergeordnete Element (domain-a). Z.B;

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: {} }));
}

Hören Sie dann im übergeordneten Fenster (Domäne-a) auf das Ereignis.

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

Schließlich setzen Sie auf Ihrem Server (http://www.domain-b.com/safari/cookiefix) den Cookie und leiten zurück zu dem Ort, von dem der Benutzer gekommen ist. Das folgende Beispiel verwendet 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/");
    }

}
12
Frank

Ich hatte das gleiche Problem und fand heute einen Fix, der für mich gut funktioniert. Wenn der Benutzeragent Safari enthält und keine Cookies gesetzt sind, leite ich den Benutzer zum OAuth Dialog:

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

Nach der Authentifizierung und der Abfrage von Berechtigungen wird das Dialogfeld OAuth================================================================================== Nach der nach nach nach nach nach nach nach nach nach nach nach nach nach nach nach nach nach nach von :

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

Der Benutzer wird also erneut auf die Registerkarte der Facebook-Seite umgeleitet, auf der bereits ein gültiger Cookie gesetzt ist , und die signierte Anfrage wird erneut gesendet.

9
Sascha Galley

Endlich habe ich mich für eine ähnliche Lösung entschieden wie Sascha, allerdings mit ein paar kleinen Anpassungen, da ich die Cookies explizit in PHP setze:

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

Dabei wird geprüft, ob der Cookie verfügbar ist, wenn der Browser auf Safari geschaltet ist. Im nächsten Schritt befinden wir uns in der Anwendungsdomäne, nämlich der oben als URL_WHERE_APP_IS_LOCATED bereitgestellten 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

}

Nach der Weiterleitung an die Anwendungsdomäne wird ein Cookie explizit gesetzt, und ich leite den Benutzer zum Autorisierungsprozess weiter.

In meinem Fall (da ich CakePHP verwende, es aber mit jedem anderen MVC-Framework problemlos funktionieren sollte) rufe ich die Anmeldeaktion erneut auf, wobei die FB-Autorisierung ein anderes Mal ausgeführt wird, und diesmal ist dies aufgrund des vorhandenen Cookies erfolgreich.

Nachdem ich die App einmal autorisiert hatte, hatte ich keine Probleme mehr mit der App mit Safari (5.1.6)

Hoffe das könnte jedem helfen.

7
Marcel Kalveram

Ich hatte dieses Problem auf Geräten mit iOS. Ich habe einen Shop erstellt, der mit einem iframe in eine normale Website eingebettet werden kann. Irgendwie bekam der Benutzer auf jeder Seite eine neue Sitzungs-ID, was dazu führte, dass Benutzer auf halbem Weg stecken blieben, weil einige Werte in der Sitzung nicht vorhanden waren.

Ich habe einige der Lösungen auf dieser Seite ausprobiert, aber Popups funktionieren auf einem iPad nicht sehr gut und ich brauchte die transparenteste Lösung.

Ich habe es mit einer Umleitung gelöst. Die Website, die meine Website einbettet, muss den Benutzer zuerst auf meine Website umleiten, sodass der obere Frame die URL zu meiner Website enthält, auf der ich ein Cookie und ein Cookie gesetzt habe Leiten Sie den Benutzer zu der richtigen Seite auf der Website weiter, auf der meine Website eingebettet ist und die in der URL angegeben ist.

Beispiel PHP code

Remote-Website leitet Benutzer weiter zu

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;

Der Benutzer landet auf http://www.domain.com/shop/frame wo meine Website eingebettet ist, speichern Sitzungen wie es sollte und Cookies essen.

Hoffe das hilft jemandem.

4
ar34z

Lassen Sie mich mein Update in ASP.NET MVC 4 teilen. Die Grundidee ist die richtige Antwort für PHP. Der nächste Code, der im Hauptlayout im Abschnitt "Header in der Nähe von Skripten" hinzugefügt wurde:

@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>
    }
}
3
Yara

Diese Lösung gilt in einigen Fällen - wenn möglich:

Wenn die iframe-Inhaltsseite eine Unterdomäne der Seite verwendet, die den iframe enthält, wird das Cookie nicht mehr blockiert.

3
eye-wonder

Hier ist ein Code, den ich verwende. Ich habe festgestellt, dass Cookies von nun an auf magische Weise im Iframe funktionieren, wenn ich Cookies von meiner Website aus setze.

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

Google hat die Katze tatsächlich aus der Tasche gelassen. Sie benutzten es eine Weile, um auf Tracking-Cookies zuzugreifen. Es wurde fast sofort behoben von Apple = \

original Wall Street Journal Post

1
Colin Godsey

Eine etwas einfachere Version in PHP von dem, was andere gepostet haben:

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

Ich habe die perfekte Antwort darauf gefunden, und zwar dank eines Mannes namens Allan, der hier alle Ehre verdient. ( http://www.allannienhuis.com/archives/2013/11/03/blocked-3rd-party-session-cookies-in-iframes/ )

Seine Lösung ist einfach und leicht zu verstehen.

Fügen Sie auf dem iframe-Inhaltsserver (Domäne 2) eine Datei mit dem Namen startsession.php auf der Stammdomänenebene hinzu, die Folgendes enthält:

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

Auf der Website der obersten Ebene mit dem Iframe (Domäne1) sollte der Aufruf der Seite mit dem Iframe folgendermaßen aussehen:

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

Und das ist es! Simples :)

Der Grund dafür ist, dass Sie den Browser auf eine URL eines Drittanbieters leiten und ihn so auffordern, dieser zu vertrauen, bevor der Inhalt im iframe angezeigt wird.

1
user1351772

Ich habe den modifizierten Whiteagle-Trick verwendet (signierter_Anforderungsparameter wurde zum Link hinzugefügt) und er hat für Safari in Ordnung funktioniert, aber IE aktualisiert die Seite in diesem Fall ständig. Meine Lösung für Safari und Internet Explorer lautet also:

$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'];
}
0
cotko

Ich habe auch unter diesem Problem gelitten, habe aber endlich die Lösung bekommen, zunächst direkt die iFrame-URL im Browser wie kleines Popup zu laden und dann nur auf die Sitzungswerte innerhalb des iFrames zuzugreifen.

0
Karthik Keyan