在 Safari 中设置跨域 cookie

发布于 2024-07-11 07:45:24 字数 409 浏览 9 评论 0 原文

我必须从域 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);

这会在我测试过的每个浏览器(Safari 除外)上设置 A.com 上的 cookie。 令人惊讶的是,即使没有 P3P 标头,这也可以在 IE6 中运行。

有什么办法可以让这个在 Safari 中工作吗?

I have to call domain A.com (which sets the cookies with http) from domain B.com.
All I do on domain B.com is (javascript):

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

This sets the cookie on A.com on every browser I've tested, except Safari.
Amazingly this works in IE6, even without the P3P headers.

Is there any way to make this work in Safari?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

梦境 2024-07-18 07:45:24

来自 Safari 开发者常见问题解答

Safari 附带了保守的 cookie 策略,该策略限制 cookie 只写入用户选择(“导航到”)的页面。 此默认的保守策略可能会使尝试写入 cookie 的基于框架的站点感到困惑并失败。

我没有找到解决这个问题的方法。

值得一提的是,如果您使用 > ,Chrome 也不会设置 cookie。 附加方法,但如果您有隐藏的 > 具有相同的来源,Chrome 可以与其他浏览器一起使用(Safari 除外)

From the Safari Developer FAQ:

Safari ships with a conservative cookie policy which limits cookie writes to only the pages chosen ("navigated to") by the user. This default conservative policy may confuse frame based sites that attempt to write cookies and fail.

I have found no way to get around this.

If it's worth anything, Chrome doesn't set the cookies either if you use the <script> appending method, but if you have a hidden <img> with the same source, Chrome works in addition to the rest of the browsers (except, again, Safari)

苏别ゝ 2024-07-18 07:45:24

这可能并不适合所有人,但我遇到了这个问题,因为我从与 API 不同的主机提供 React 应用程序,最终有效的解决方案是使用 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 不是您或合作伙伴的,则这将不起作用(至少对于面向最终用户的内容不起作用)。

This might not work for everyone, but I came across this issue because I was serving a React App from a different host than the API, and the solution that ultimately worked was to use DNS:

Our client was being served from www.company-name.com and our API was on company-name.herokuapp.com. By making a CNAME record api.company-name.com --> company-name.herokuapp.com, and having our client use that subdomain for API calls, Safari stopped considering it a "third-party" cookie.

The upside is that there's very little code involved, and it's all using well-established stuff... The downside is that you need some control/ownership over the API host if you're going to use https - they need a certificate that's valid for the client domain, or users will get a certificate warning - so this wouldn't work (at least not for something end-user-facing) if the API in question isn't yours or a partner's.

谈场末日恋爱 2024-07-18 07:45:24

工作方法 2014-2016:

您必须对域执行 window.open / 分配 cookie / 关闭弹出窗口,该域现已列入安全列表。

原始帖子@ PHP 多个 cookie 无法在 iPad / iPhone 浏览器上工作< /a>

Working method 2014-2016:

You have to do window.open to the domain / assign a cookie / close the popup, the domain is now safelisted.

Original post @ PHP multiple cookies not working on iPad / iPhone browser

噩梦成真你也成魔 2024-07-18 07:45:24

假设他们安装了闪存,就会有一些邪恶的伎俩。

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

本地共享对象教程

但是,实现起来可能很复杂,可以说至少。

此外,LSO 正逐渐成为安全噩梦:

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

There is a bit of an evil trick assuming they have flash installed.

I'm not sure if it still works or not, but Flash'es "Local Shared Objects" aka Flash Cookies could help you circumnavigate Safari's same-domain policies.

Local Shared Object Tutorial

However, it may be complicated to implement, to say the least.

Additonally, LSO's are comming into the light as being a security nightmare:

So think carefully before using them.

蓝眸 2024-07-18 07:45:24

发布到隐藏的

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

A post to a hidden <iframe> can allow you to by-pass this restriction in 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>
夜空下最亮的亮点 2024-07-18 07:45:24

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 url 中:

iframe.setAttribute('url','x.com/?cookieval='+YOUR_COOKIE_GET_METHOD('cookiename'));

There is a proper workaround for this working in 2015. Let's say there is website y.com which includes iframe with site x.com. The x.com iframe wants to store a cookie. That is not permitted by Safari policy, however, y.com is able to store it. So y.com must listen to messages from x.com and then store the cookie itself.

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

When x.com needs to store the cookie, it must post a message to y.com:

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

Also you can work your way to post message to the iframe if you want to read the cookie. Or you can include it as parameter in x.com iframe url using javascript:

iframe.setAttribute('url','x.com/?cookieval='+YOUR_COOKIE_GET_METHOD('cookiename'));
半世晨晓 2024-07-18 07:45:24

我们在工作中刚刚想出的一个解决方法是通过 window.open() 设置 cookie - 它可能不是您的最佳选择(因为您将打开一个丑陋的弹出窗口),但它对我们来说效果很好。 无论如何,我们必须打开一个弹出窗口才能进行 OAuth 身份验证。

因此,我们所做的要点是:

  1. 用户单击 B.com 中的链接
  2. 弹出窗口打开到 A.com/setCookie
  3. A.com 设置其 cookie,然后在正确的位置重定向到 B.com

再次强调,全部无效解决方案,但它在我们的解决方案中有效。 希望这可以帮助。

A workaround we just came up with at my job was to set the cookie via a window.open() - it may not be optimal for you (as you'll have an ugly ass popup window open), but it worked well for us. We had to have a popup window open anyway for OAuth authentication.

So the jist of what we did was:

  1. User clicks a link from B.com
  2. Popup window opens to A.com/setCookie
  3. A.com sets its cookie, and then redirects to B.com in the proper place

Again, not valid in all solutions, but it worked in ours. Hope this helps.

难得心□动 2024-07-18 07:45:24

我知道这个问题相当老了,但这帮助我解决了 cookie 问题:在

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

cookieForm.submit();

设置 cookie 的页面上发布表单的想法。

I know this question is rather old, but this helped me to solve cookies problem:

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

cookieForm.submit();

The idea to make a form post on a page that sets your cookies.

你丑哭了我 2024-07-18 07:45:24

*编辑*
据报道,此解决方法已在 WebKit 中关闭。

卢卡,

好吧,这个答案已经有两年了,但是...如果您将表单发布到隐藏的 iframe,则可以从 iframe 设置 cookie。 您可以通过创建一个表单来做到这一点:

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

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

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

您可以侦听 iframe 的 onload,或者可以让 iframe 操作页面发出一些表示加载信号的 javascript。 我已经在 Safari 和 Chrome 中对此进行了测试,并且有效。

干杯。

*EDIT*
This workaround has been reported closed in WebKit.

Luca,

Ok, so this answer is two years old, but... you can set a cookie from an iframe if you post a form to a hidden iframe. You can do this by creating a form:

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

Then in Javascript, get a reference to the form and call submit:

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

You can listen to the iframe's onload, or you can have your iframe action page issue some javascript that signals the load. I have tested this in Safari and Chrome, and it works.

Cheers.

我恋#小黄人 2024-07-18 07:45:24

也许务实地创建并单击带有 href="A.com/setCookie?cache=1231213123" 和指向隐藏 iframe 的目标属性的链接。 这可能绕过Safari设置cookie的用户导航策略(我没有方便测试的Safari。)

Perhaps pragmatically create and click a link with an href="A.com/setCookie?cache=1231213123" and a target attribute pointing to a hidden iframe. That may bypass Safari's policy of user navigation for setting cookies (I don't have Safari handy to test.)

耶耶耶 2024-07-18 07:45:24

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

I did some extensive investigation around this when I was trying to deploy a site that used Windows Live ID, which depended on the ability to be able to set 3rd party cookies in order to log out. It just... didn't work. Nothing we could do would get it to work. The Live ID team also did extensive investigation and their answer was "can't make it work".

弥枳 2024-07-18 07:45:24

请注意这一行:

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

在添加 http 之前我无法使其正常工作,即

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

Note this line:

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

I could not get this working until I added the http, i.e.

script.src = "http://A.com/setCookie?cache=1231213123";
檐上三寸雪 2024-07-18 07:45:24

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

I found a simple solution. You just need for first time setting cookie to check if request come from the same origin or not, if not as usual you need to return into iframe a script that will repeat this request, already having permission to assign cookie. After that you can do other request directly through iframe accessing this cookie. This helped me in my tracking system. Try, this works well.

甜味拾荒者 2024-07-18 07:45:24

值得注意的是,Safari 中的此限制不适用于跨子域。 因此,如果您直接访问 sitea.com,则可以从 subdomain.sitea.com 设置 cookie,而无需直接用户交互(iframe/JavaScript)。

这与我开发 API 时的案例相关。 如果您的访问者到达 mysite.com,然后您希望一些 JavaScript 与您的 API 进行交互,那么如果该 API 托管在 api.mysite.com,那么它将在 Safari 上运行。

Its worth noting that this restriction in Safari doesn't apply across subdomains. So if you directly visit sitea.com, then you can set cookies from subdomain.sitea.com without direct user interaction (iframe/JavaScript).

This was relevant for my case when developing an API. If you're visitors are arriving at mysite.com, and then you want some JavaScript to interact with your API, then if the API is hosted at api.mysite.com, then it will work on Safari.

倦话 2024-07-18 07:45:24

将此 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.php首先访问index.html,检查浏览器是否是Safari,以及名称为“activated”的GET参数是否不存在。 如果满足这两个条件(这将在第一次访问 Safari 浏览器时发生),则浏览器将重定向到 http ://example2.com/activate.php 带有 GET 参数“callback”,包含附加有“activated”参数的调用 URL。

  2. http://example2.com/activate.php 只是重定向回包含在GET 参数,“回调”。

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

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

Place this JavaScript on the page making cross-domain requests, 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>

Then create a file on the other server, which needs to set cookies, 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();
  }
  ?>

Here's how this works:

  1. When http://example1.com/index.html is first visited, a check is made to see whether the browser is Safari and whether a GET parameter of the name "activated" does not exist. If both conditions are met (which will happen on the first visit for a Safari browser), then the browser is redirected to http://example2.com/activate.php with a GET parameter, "callback", containing the calling URL appended with an "activated" parameter.

  2. http://example2.com/activate.php simply redirects back to the URL contained in the GET parameter, "callback".

  3. When http://example1.index.html is now hit this second time after being redirected-to, the GET parameter, "activated" will now be set, so the conditional from step 1 will not execute, thus allowing the script to continue execution.

This fulfills Safari's requirement of having the browser visit the 3rd party domain at least once in order to start setting cookies.

难以启齿的温柔 2024-07-18 07:45:24

尝试类似的操作:

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

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

Try something like:

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

It may bypass safari's security policy.

划一舟意中人 2024-07-18 07:45:24

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

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

It isn't the missing type-attribute thats annoying you ?-)

<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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文