O truque de iframe de cookie de terceiros do Safari não funciona mais?

Então essa é a décima quinta vingança da pergunta “como obtenho cookies de terceiros para trabalhar no Safari”, mas estou perguntando novamente porque acho que o campo de jogo mudou, talvez depois de fevereiro de 2012. Um dos truques padrão para obter o terceiro Os cookies de festa no Safari eram os seguintes: use algum javascript para POST para um iframe oculto. Isso costumava levar o Safari a pensar que o usuário havia interagido com o conteúdo de terceiros e, assim, permitir que os cookies fossem configurados.

Eu acho que essa lacuna foi fechada na sequência do escândalo leve, onde foi revelado que o Google estava usando esse truque com seus anúncios. No mínimo, ao usar esse truque, não consegui colocar cookies no Safari. Eu descobri algumas postagens aleatórias na Internet que afirmavam que a Apple estava trabalhando para fechar a brecha, mas eu não encontrei nenhuma palavra oficial.

Como substituto, até tentei redesenhar o quadro principal de terceiros para que você tivesse que clicar em um botão antes que o conteúdo fosse carregado, mas mesmo esse nível de interação direta não foi suficiente para derreter o coração frio do Safari.

Então, alguém sabe ao certo se o Safari realmente fechou essa lacuna? Em caso afirmativo, existem outras soluções alternativas (além de include manualmente um ID de session em cada solicitação)?

Só queria deixar aqui uma solução de trabalho simples que não requer interação do usuário .

Como afirmei em um post que fiz :

Basicamente tudo que você precisa fazer é carregar sua página no top.location, criar a session e redirecioná-lo de volta para o Facebook.

Adicione este código na parte superior do seu index.php e defina $page_url na guia final da aplicação / URL da aplicação e verá que a sua aplicação funcionará sem qualquer problema.

    

Nota: Isto foi feito para o facebook, mas funcionaria em qualquer outra situação semelhante.


Edit 20-Dec-2012 – Mantendo o Pedido Assinado:

O código acima não mantém as solicitações de dados de postagem, e você perderia o signed_request, se o seu aplicativo depender de uma solicitação assinada, sinta-se à vontade para experimentar o seguinte código:

Nota: Isso ainda está sendo testado corretamente e pode ser menos estável que a primeira versão. Use por sua conta e risco / Feedback é apreciado.

(Obrigado ao CBroe por me apontar na direção certa aqui permitindo melhorar a solução)

 // 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(''); // End Session Fix 

Você disse que estava disposto a fazer com que seus usuários cliquem em um botão antes que o conteúdo seja carregado. Minha solução foi ter um botão para abrir uma nova janela do navegador. Essa janela define um cookie para o meu domínio, atualiza o abridor e depois fecha.

Então, seu script principal poderia se parecer com:

  0): ?>   Click here to load content  

Então safari_cookie_fix.php se parece com:

    Safari Fix     This window should close automatically   

Eu enganei o Safari com um .htaccess:

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

E parou de funcionar para mim também. Todos os meus aplicativos estão perdendo a session no Safari e estão redirecionando para fora do Facebook. Como estou com pressa para corrigir esses aplicativos, atualmente estou procurando uma solução. Eu vou manter você informado.

Edit (2012-04-06): Aparentemente, a Apple “fixa” com 5.1.4. Tenho certeza de que esta é a reação à questão do Google: “Havia um problema na aplicação de sua política de cookies. Sites de terceiros poderiam definir cookies se a preferência” Bloquear Cookies “no Safari estivesse definida como a configuração padrão de” De terceiros e anunciantes “. http://support.apple.com/kb/HT5190

No seu controlador Ruby on Rails, você pode 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 => "" end end end 

Para minha situação específica, resolvi o problema usando window.postMessage () e eliminei qualquer interação do usuário. Note que isto só funcionará se você puder de alguma forma executar js na janela pai. Incluindo um js do seu domínio ou se você tiver access direto à origem.

No iframe (domínio-b), eu verifico a presença de um cookie e, se não estiver configurado, envia uma mensagem postMessage para o pai (domínio-a). Por exemplo;

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

Em seguida, na janela pai (domínio-a), ouça o 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, no seu servidor (http://www.domain-b.com/safari/cookiefix) você define o cookie e redireciona de volta para onde o usuário veio. Abaixo exemplo está usando o 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/"); } } 

Eu tive o mesmo problema e hoje encontrei uma correção que funciona bem para mim. Se o agente do usuário contiver o Safari e nenhum cookie for definido, redirectei o usuário para a checkbox de diálogo OAuth:

  0 && strpos($_SERVER['HTTP_USER_AGENT'], 'Safari')) { ?>   

Após a autenticação e a solicitação de permissions, o Diálogo OAuth redirectá para o meu URI no local superior. Então, definir cookies é possível. Para todos os nossos aplicativos de canvas e guia de páginas, já incluí o seguinte script:

  

Assim, o usuário será redirecionado novamente para a guia da página do Facebook com um cookie válido já definido e a solicitação assinada será postada novamente.

Eu finalmente fui para uma solução similar àquela que o Sascha forneceu, porém com um pequeno ajuste, já que estou definindo os cookies explicitamente em 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 ''; 

O que isto faz é verificar se o cookie está disponível quando o navegador é safari. Na próxima etapa, estamos no domínio do aplicativo, ou seja, o URI fornecido como URL_WHERE_APP_IS_LOCATED acima.

 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 } 

Portanto, depois de redirect para o domínio do aplicativo, um cookie é definido explicitamente e eu redireciono o usuário para o processo de autorização.

No meu caso (já que estou usando o CakePHP, mas ele deve funcionar bem com qualquer outra estrutura MVC), estou chamando a ação de login novamente onde a autorização do FB é executada outra vez e desta vez é bem-sucedida devido ao cookie existente.

Depois de ter autorizado o aplicativo uma vez, não tive mais problemas ao usar o aplicativo com o Safari (5.1.6)

Espero que isso possa ajudar alguém.

Eu tive esse problema em dispositivos que executam o iOS. Eu fiz uma loja que é incorporada em um site normal usando um iframe. De alguma forma, em cada pageload, o usuário obtinha um novo ID de session, resultando em usuários ficando presos no meio do processo, porque alguns valores não estavam presentes na session.

Eu tentei algumas das soluções dadas nesta página, mas os popups não funcionam muito bem em um iPad e eu precisava da solução mais transparente.

Eu resolvi usando um redirecionamento. O site que incorpora o meu site deve primeiro redirect o usuário para o meu site, então o quadro superior contém o URL do meu site, onde eu defino um cookie e redireciono o usuário para a página adequada no site que incorpora o meu site, que é passado através da url.

Exemplo de código PHP

Site remoto redireciona o usuário para

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

init.php

  

O usuário acaba em http://www.domain.com/shop/frame onde meu site é incorporado, armazenando sessões como deveria e comendo cookies.

Espero que isso ajude alguém.

Deixe-me compartilhar minha correção no ASP.NET MVC 4. A ideia principal é como na resposta correta para o PHP. O próximo código adicionado no layout principal no header próximo à seção 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) {  } } 

Esta solução se aplica em alguns casos – se possível:

Se a página de conteúdo do iframe usar um subdomínio da página que contém o iframe, o cookie não será mais bloqueado.

O Google, na verdade, deixou o gato sair da sacola dessa vez. Eles estavam usando isso por um tempo para acessar cookies de rastreamento. Foi corrigido quase imediatamente pela Apple = \

publicação original do Wall Street Journal

Aqui está algum código que eu uso. Descobri que, se eu definir qualquer cookie no meu site, os cookies funcionam magicamente no iframe a partir de então.

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 "\n\n"; 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 "\n\n"; exit(); } 

Uma versão ligeiramente simplificada em PHP do que os outros postaram:

 if (!isset($_COOKIE, $_COOKIE['PHPSESSID'])) { print ''; exit(); } if (isset($_GET['start_session'])) { header("Location: https://apps.facebook.com/YOUR_APP_ID/"); exit(); } 

Eu encontrei a resposta perfeita para isso, tudo graças a um cara chamado Allan que merece todo o crédito aqui. ( http://www.allannienhuis.com/archives/2013/11/03/blocked-3rd-party-session-cookies-in-iframes/ )

Sua solução é simples e fácil de entender.

No servidor de conteúdo iframe (domínio 2), adicione um arquivo chamado startsession.php no nível do domínio raiz que contém:

  

Agora, no site de nível superior que contém o iframe (domínio1), a chamada para a página que contém o iframe deve se parecer com:

 page with iFrame 

E é isso! Simples 🙂

A razão pela qual isso funciona é que você está direcionando o navegador para um URL de terceiros e, assim, dizendo a ele para confiar nele antes de exibir o conteúdo dele no iframe.

Eu usei modificado (adicionado signed_request param para o link) truque de Whiteagle e funcionou ok para o safari, mas o IE está constantemente atualizando a página nesse caso. Então minha solução para safari e 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) { ?>   

Eu também tenho sofrido com esse problema, mas finalmente consegui a solução, inicialmente diretamente a carregar o URL do iframe no navegador como pequeno pop-up e só acessar os valores da session dentro do iframe.

Eu recentemente acertei o mesmo problema no Safari. A solução que descobri baseia-se na API HTML5 de armazenamento local. Usando o armazenamento local, você pode emular cookies.

Aqui está o meu post com detalhes: http://log.scalemotion.com/2012/10/how-to-trick-safari-and-set-3rd-party.html

Eu decidi me livrar da variável $_SESSION todos juntos e escrevi um wrapper em torno do memcache para imitar a session.

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

Caso de uso: No momento em que um usuário acessa o aplicativo, armazene a solicitação assinada usando o Session_manager e, como ele está no cache, você poderá acessá-lo em qualquer página daqui em diante.

Nota: Isso não funcionará ao navegar de forma privada no Safari desde que o session_id seja redefinido toda vez que a página for recarregada. (Estúpido safári)

Você pode resolver este problema, adicionando o header como política p3p .. eu tive o mesmo problema no safari assim depois de adicionar o header em cima dos arquivos resolveu o meu problema.