javascript facebook iframe safari

javascript - ¿El truco del iframe de cookies de Safari de terceros ya no funciona?



facebook (19)

Aquí hay un código que uso. Descubrí que si configuro una cookie de mi sitio, las cookies funcionan mágicamente en el iframe a partir de ese momento.

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

Esta es la decimoquinta venganza de la pregunta "¿Cómo obtengo las cookies de terceros para trabajar en Safari?", Pero vuelvo a preguntar porque creo que el campo de juego ha cambiado, tal vez después de febrero de 2012. Uno de los trucos estándar para obtener 3er. las cookies de fiesta en Safari eran las siguientes: usar algunos javascript para POSTAR a un iframe oculto. Sirve para engañar a Safari y hacerle pensar que el usuario ha interactuado con el contenido de terceros y, por lo tanto, permite establecer cookies.

Creo que esta escapatoria se ha cerrado a raíz del leve escándalo en el que se reveló que Google usaba ese truco con sus anuncios. Por lo menos, al usar este truco he sido completamente incapaz de establecer cookies en Safari. Descubrí algunas publicaciones en Internet al azar que afirmaban que Apple estaba trabajando para cerrar la brecha, pero no he encontrado ninguna palabra oficial.

Como alternativa, incluso traté de rediseñar el marco principal de terceros para que tuviera que hacer clic en un botón antes de que se cargara el contenido, pero incluso ese nivel de interacción directa no era suficiente para derretir el corazón frío y frío de Safari.

Entonces, ¿alguien sabe con certeza si Safari efectivamente ha cerrado esta laguna? Si es así, ¿hay otras soluciones (aparte de incluir manualmente una ID de sesión en cada solicitud)?


Decidí deshacerme de la variable $_SESSION todos juntos y escribí un contenedor alrededor de Memcache para imitar la sesión.

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

Caso de uso: en el momento en que un usuario llega a la aplicación, almacene la solicitud firmada usando Session_manager y dado que está en la memoria caché, puede acceder a ella en cualquier página a partir de ese momento.

Nota: Esto no funcionará cuando se navegue de forma privada en Safari ya que session_id se restablece cada vez que la página se vuelve a cargar. (Stupid Safari)


Dijiste que estabas dispuesto a hacer que tus usuarios hagan clic en un botón antes de que se cargue el contenido. Mi solución fue tener un botón para abrir una nueva ventana del navegador. Esa ventana establece una cookie para mi dominio, actualiza el abridor y luego se cierra.

Para que tu guión principal se vea así:

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

Entonces safari_cookie_fix.php se ve así:

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


En su controlador Ruby on Rails puede usar:

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


Esta solución se aplica en algunos casos, si es posible:

Si la página de contenido de iframe usa un subdominio de la página que contiene el iframe, la cookie ya no está bloqueada.


Finalmente, opté por una solución similar a la que proporcionaba Sascha, sin embargo, con algunos pequeños ajustes, ya que estoy configurando las cookies explícitamente en PHP:

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

Lo que hace es verificar si la cookie está disponible cuando el navegador es safari. En el siguiente paso, estamos en el dominio de la aplicación, es decir, el URI proporcionado como URL_WHERE_APP_IS_LOCATED arriba.

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 }

Entonces, después de redireccionar al dominio de la aplicación, se establece explícitamente una cookie y redirijo al usuario al proceso de autorización.

En mi caso (ya que estoy usando CakePHP pero debería funcionar bien con cualquier otro framework MVC) llamo a la acción de inicio de sesión nuevamente donde la autorización FB se ejecuta en otro momento, y esta vez tiene éxito debido a la cookie existente.

Después de haber autorizado la aplicación una vez, no tuve más problemas al usar la aplicación con Safari (5.1.6)

Espero que pueda ayudar a cualquiera.


Google realmente dejó al gato fuera de la bolsa en este caso. Lo estaban usando por un tiempo para acceder a las cookies de seguimiento. Fue arreglado casi de inmediato por Apple = /

publicación original del Wall Street Journal



He encontrado la respuesta perfecta para esto, todo gracias a un tipo llamado Allan que merece todo el crédito aquí. ( http://www.allannienhuis.com/archives/2013/11/03/blocked-3rd-party-session-cookies-in-iframes/ )

Su solución es simple y fácil de entender.

En el servidor de contenido iframe (dominio 2), agregue un archivo llamado startsession.php en el nivel de dominio raíz que contiene:

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

Ahora, en el sitio web de nivel superior que contiene el iframe (dominio1), la llamada a la página que contiene el iframe debe verse así:

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

¡Y eso es! Simples :)

El motivo por el que esto funciona es porque está dirigiendo el navegador a una URL de un tercero y, por lo tanto, diciéndole que confíe en él antes de mostrar contenido dentro del marco flotante.


Para mi situación específica, resolví el problema usando window.postMessage () y eliminando cualquier interacción del usuario. Tenga en cuenta que esto solo funcionará si de alguna manera puede ejecutar js en la ventana principal. O haciendo que incluya un js de su dominio, o si tiene acceso directo a la fuente.

En el iframe (dominio-b) compruebo la presencia de una cookie y, si no está configurada, enviaré un postMessage al padre (domain-a). P.ej;

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

Luego, en la ventana principal (dominio-a) escuche el evento.

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

Finalmente, en su servidor (http://www.domain-b.com/safari/cookiefix) configura la cookie y la redirecciona de vuelta al lugar de donde proviene el usuario. El ejemplo siguiente es el uso de 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/"); } }


Permítanme compartir mi corrección en ASP.NET MVC 4. La idea principal es la respuesta correcta para PHP. El siguiente código agregado en el diseño principal en el encabezado cerca de la sección de scripts:

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


Puede resolver este problema agregando el encabezado como política p3p. Tengo el mismo problema en safari, por lo que después de agregar el encabezado en la parte superior de los archivos, resolvió mi problema.

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


Solo quería dejar aquí una solución de trabajo simple que no requiera la interacción del usuario .

Como dije en una publicación que hice :

Básicamente, todo lo que necesita hacer es cargar su página en top.location, crear la sesión y redirigirla de nuevo a Facebook.

Agregue este código en la parte superior de su index.php y configure $page_url en la pestaña final de la aplicación / URL de la aplicación y verá que su aplicación funcionará sin ningún problema.

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

Nota: Esto fue hecho para Facebook, pero realmente funcionaría en cualquier otra situación similar.

Editar 20-dic-2012 - Mantenimiento de solicitud firmada:

El código anterior no mantiene las solicitudes de datos de la publicación y perderá la solicitud firmada. Si su aplicación se basa en la solicitud firmada, puede probar el siguiente código:

Nota: Esto todavía se está probando correctamente y puede ser menos estable que la primera versión. Utilice bajo su propio riesgo / Comentarios se aprecia.

(Gracias a CBroe por indicarme la dirección correcta que permite mejorar la solución)

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


También he estado sufriendo este problema, pero finalmente obtuve la solución. Inicialmente, directamente cargaba la url del iframe en el navegador como una pequeña ventana emergente y luego solo accedía a los valores de la sesión dentro del iframe.


Tuve el mismo problema y hoy encontré una solución que funciona bien para mí. Si el agente de usuario contiene Safari y no se establecen cookies, redirijo al usuario al cuadro de diálogo 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 } ?>

Después de la autenticación y de solicitar permisos, el cuadro de diálogo OAuth redirigirá a mi URI en la ubicación superior. Entonces establecer cookies es posible. Para todas nuestras aplicaciones de lienzo y pestaña de página, ya incluí el siguiente script:

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

Entonces el usuario será redirigido de nuevo a la pestaña de la página de Facebook con una cookie válida ya configurada y la solicitud firmada se publica nuevamente.


Tuve este problema en dispositivos con iOS. Hice una tienda que se puede insertar en un sitio web normal utilizando un iframe. De alguna forma, en cada carga de página, el usuario obtenía un nuevo sessionid, lo que provocaba que los usuarios se quedaran atrapados a mitad del proceso porque algunos valores no estaban presentes en la sesión.

Probé algunas de las soluciones proporcionadas en esta página, pero las ventanas emergentes no funcionan muy bien en un iPad y necesitaba la solución más transparente.

Lo resolví usando una redirección. El sitio web que integra mi sitio primero debe redireccionar al usuario a mi sitio, por lo que el marco superior contiene la URL de mi sitio, donde configuro una cookie y redirijo al usuario a la página correcta en el sitio web que incrusta mi sitio, que se pasa a través de la url.

Ejemplo de código PHP

El sitio web remoto redirecciona al usuario a

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;

El usuario termina en http://www.domain.com/shop/frame donde está incrustado mi sitio, almacenando sesiones como debería y comiendo cookies.

Espero que esto ayude a alguien.


Una versión ligeramente simple en PHP de lo que otros han publicado:

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


Usé el truco modificado de Whiteagle (se agregó el param firmado firmado al enlace) y funcionó bien para safari, pero IE actualiza constantemente la página en ese caso. Entonces mi solución para Safari e Internet Explorer es:

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


Yo engañé a Safari con .htaccess:

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

Y dejó de funcionar para mí también. Todas mis aplicaciones están perdiendo la sesión en Safari y están redireccionando desde Facebook. Como tengo prisa por arreglar esas aplicaciones, actualmente estoy buscando una solución. Te mantendré informado.

Editar (2012-04-06): Aparentemente, Apple lo "arregló" con 5.1.4. Estoy seguro de que esta es la reacción a lo de Google: "Existía un problema en la aplicación de su política de cookies. Los sitios web de terceros podían establecer cookies si la preferencia" Bloquear cookies "en Safari se configuraba con la configuración predeterminada" De terceros y anunciantes ". http://support.apple.com/kb/HT5190