在Safari中设置跨域cookie

时间:2009-01-03 04:08:16

标签: javascript safari cookies cross-domain cross-site

Evernote的bookmarklet能够做到这一点,因此即使赏金将以非生产性的方式进行,最受欢迎的答案也不会回答这个问题。

我必须从域B.com调用域A.com(使用http设置cookie)。 我在域名B.com上做的就是(javascript):

var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.src = "A.com/setCookie?cache=1231213123";
head.appendChild(script);

这会在我测试的每个浏览器上设置A.com上的cookie,但Safari除外。 令人惊讶的是,即使没有P3P标题,这也适用于IE6。

有什么方法可以让它在Safari中运行吗?

18 个答案:

答案 0 :(得分:54)

来自Safari Developer FAQ

  

Safari附带保守的cookie策略,该策略将cookie写入仅限于用户选择(“导航到”)的页面。此默认保守策略可能会混淆尝试写入cookie并失败的基于帧的站点。

我发现无法解决这个问题。

如果您有任何价值,如果您使用<script&gt; Chrome,则Chrome不会设置Cookie。附加方法,但如果您有隐藏的<img&gt;使用相同的来源,除了其他浏览器(除了Safari)之外,Chrome还可以使用

答案 1 :(得分:13)

答案 2 :(得分:6)

2014 - 2016年工作方法:

你必须对window.open进行域名/分配cookie /关闭弹出窗口,域名现在已经过安全列表。

原帖@ PHP multiple cookies not working on iPad / iPhone browser

答案 3 :(得分:4)

假设安装了闪光灯,有一个邪恶的技巧。

我不确定它是否仍然有效,但Flash'es“本地共享对象”又名 Flash Cookie 可以帮助您绕过Safari的同域策略。

Local Shared Object Tutorial

然而,至少可以说,实施起来可能很复杂。

此外,LSO正在成为一场安全噩梦:

因此在使用它们之前要仔细考虑。

答案 4 :(得分:3)

2015年有一个正确的解决方法。假设网站y.com包含网站x.com的iframe。 x.com iframe想要存储cookie。 Safari政策不允许这样做,但y.com能够存储它。因此,y.com必须收听来自x.com的消息,然后存储cookie本身。

var _cookieEvMth = window.addEventListener ? "addEventListener" : "attachEvent";
var _cookieEvAction = window[_cookieEvMth];
var _cookieEv = _cookieEvMth == "attachEvent" ? "onmessage" : "message";
_cookieEvAction(_cookieEv, function(evt){
  if(evt.data.indexOf('cookieset')!=-1){
    var datack = evt.data.split('|');
    YOUR_CUSTOM_COOKIE_SAVE_METHOD(datack[1],datack[2],datack[3]);
  }
},false);

当x.com需要存储cookie时,它必须向y.com发送消息:

window.parent.postMessage('cookieset|'+ckName+'|'+ckVal+'|'+days,'*');

如果您想要阅读cookie,您也可以按照自己的方式将消息发布到iframe。或者您可以使用javascript:

将其作为参数包含在x.com iframe网址中
iframe.setAttribute('url','x.com/?cookieval='+YOUR_COOKIE_GET_METHOD('cookiename'));

答案 5 :(得分:3)

隐藏<iframe>的帖子可以让您在Safari中绕过此限制 - http://gist.github.com/586182

<?php
  header('P3P: CP=HONK');
  setcookie('test_cookie', '1', 0, '/');
?>
<div id="test_cookie" style="position: absolute; top: -10000px"></div>
<script>
  window.setTimeout(function() {
    if (document.cookie.indexOf('test_cookie=1') < 0) {
      var      
        name = 'test_cookie',
        div = document.getElementById(name),
        iframe = document.createElement('iframe'),
        form = document.createElement('form');

      iframe.name = name;
      iframe.src = 'javascript:false';
      div.appendChild(iframe);

      form.action = location.toString();
      form.method = 'POST';
      form.target = name;
      div.appendChild(form);

      form.submit();
    }
  }, 10);
</script>

答案 6 :(得分:2)

我知道这个问题相当陈旧,但这有助于我解决Cookie问题:

var cookieForm = document.createElement("form");
cookieForm.action = "A.com/setCookie?cache=1231213123";
cookieForm.method = "post";
document.body.appendChild(cookieForm);

cookieForm.submit();

在设置Cookie的网页上发布表单的想法。

答案 7 :(得分:2)

我们刚刚在我的工作中提出的解决方法是通过window.open()设置cookie - 它可能不适合你(因为你将打开一个丑陋的屁股弹出窗口),但它有效对我们好我们必须打开一个弹出窗口进行OAuth身份验证。

所以我们所做的就是:

  1. 用户点击B.com的链接
  2. 弹出窗口将打开A.com/setCookie
  3. A.com设置其cookie,然后在适当的位置重定向到B.com
  4. 同样,在所有解决方案中都无效,但它在我们的解决方案中有效。希望这会有所帮助。

答案 8 :(得分:1)

*的 修改 * 据报道,此解决方法已在WebKit中关闭。

卢卡,

好的,所以这个答案已经有两年了,但是......如果你把一个表格发布到一个隐藏的iframe,你可以从iframe设置一个cookie。您可以通过创建表单来完成此操作:

<form id="myiframe" action="http://yourdomain.com" method="POST" target="iframe_target">

然后在Javascript中,获取对表单的引用并调用submit:

document.getElementsByTagName('form')[0].submit();

您可以收听iframe的onload,也可以让iframe操作页面发出一些指示负载的javascript。我已经在Safari和Chrome中对此进行了测试,但它确实有效。

干杯。

答案 9 :(得分:1)

这可能不适用于每个人,但是我遇到了这个问题,因为我是从不同于API的主机提供React App的,最终可行的解决方案是使用DNS:

我们的客户来自www.company-name.com,而我们的API位于company-name.herokuapp.com。通过制作 CNAME 记录api.company-name.com-> company-name.herokuapp.com,并让我们的客户端使用该子域进行API调用,Safari停止了将其视为“第三方“ Cookie。

好处是涉及的代码很少,而且全部都使用了完善的东西...缺点是,如果要使用https,则需要对API主机进行一些控制/所有权-它们需要一个对于客户端域有效的证书,否则用户将收到证书警告-因此,如果所涉及的API不是您的或合作伙伴的API,那么它将不起作用(至少不适用于面向最终用户的事情)。

答案 10 :(得分:0)

请注意以下这一行:

script.src = "A.com/setCookie?cache=1231213123";

直到我添加了http,即

,我才能解决这个问题
script.src = "http://A.com/setCookie?cache=1231213123";

答案 11 :(得分:0)

当我尝试部署使用Windows Live ID的网站时,我对此进行了一些广泛的调查,这取决于是否能够设置第三方Cookie以便注销。它只是......没有用。我们所做的一切都无法让它发挥作用。 Live ID团队也进行了广泛的调查,答案是“无法使其发挥作用”。

答案 12 :(得分:0)

也许实际创建并点击包含href="A.com/setCookie?cache=1231213123"的链接和指向隐藏iframe的目标属性。 可能绕过Safari的用户导航政策来设置Cookie(我没有Safari方便测试。)

答案 13 :(得分:0)

我找到了一个简单的解决方案。您只需要第一次设置cookie来检查请求是否来自同一来源,如果不像往常一样,您需要返回iframe一个将重复此请求的脚本,已经拥有分配cookie的权限。之后,您可以直接通过iframe访问此cookie来执行其他请求。这有助于我的跟踪系统。试试,这很有效。

答案 14 :(得分:0)

值得注意的是,Safari中的这种限制并不适用于子域。因此,如果您直接访问sitea.com,则可以在没有直接用户交互(iframe / JavaScript)的情况下从subdomain.sitea.com设置cookie。

这与我开发API时的情况相关。如果您的访问者到达mysite.com,然后您想要一些JavaScript与您的API进行交互,那么如果API在api.mysite.com上托管,那么它将适用于Safari。

答案 15 :(得分:0)

将此JavaScript放在发出跨域请求http://example1.com/index.html的页面上:

  <script>
  var gup = function(name, url) {
     if(!url) url = location.href;
     name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
     var regexS = "[\\?&]"+name+"=([^&#]*)";
     var regex = new RegExp( regexS );
     var results = regex.exec( url );
     return results == null ? null : results[1];
  }
  var isSafari = navigator.vendor && navigator.vendor.indexOf('Apple') > -1 && navigator.userAgent && !navigator.userAgent.match('CriOS');
  var n = gup("activated");
  if(isSafari && n == null) {
     //browser is Safari and cookies have not yet been activated
     var current_url = location.protocol + '//' + location.host + location.pathname;
     var query_string = '?callback=' + encodeURIComponent(current_url + '?activated=1');
     var new_url = 'http://example2.com/activate.php' + query_string;
     window.location.href = new_url;
  }
  //the rest of your code goes here, and you can now set cross-domain cookies on Safari
  </script>

然后在另一台服务器上创建一个文件,该文件需要设置Cookie http://example2.com/activate.php

  <?php
  if(isset($_GET['callback'])) {
     header('Location: '.$_GET['callback']);
     exit();
  } else {
     //in case callback param is not set, simply go back to previous page
     echo "<script>";
     echo "window.history.back();";
     echo "</script>";
     exit();
  }
  ?>

这是它的工作方式:

  1. 首次访问http://example1.com/index.html时,将检查浏览器是否为Safari,以及是否不存在名称为“ activated”的GET参数。如果同时满足这两个条件(在Safari浏览器的首次访问中会发生),则使用GET参数“ callback”将浏览器重定向到http://example2.com/activate.php,该参数包含调用URL并附加“ activated”参数。

  2. http://example2.com/activate.php仅重定向回GET参数“ callback”中包含的URL。

  3. 当重定向到http://example1.index.html后第二次点击该命令时,现在将设置GET参数“ activated”,因此将不执行步骤1中的条件,从而允许该脚本继续执行。

这满足了Safari要求浏览器至少访问一次第三方域以开始设置cookie的要求。

答案 16 :(得分:-2)

尝试类似:

var w = window.open("A.com/setCookie?cache=1231213123");
w.close();

它可能会绕过safari的安全政策。

答案 17 :(得分:-12)

这不是缺少类型属性让你烦恼吗? - )

<script type="text/javascript">
  var head = document.getElementsByTagName("head")[0];
  var script = document.createElement("script");
  script.setAttribute("type","text/javascript");
  script.src = "A.com/setCookie?cache=1231213123";
  head.appendChild(script);
</script>