在 Safari 中设置跨域 cookie
我必须从域 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 中工作吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(18)
来自
Safari 开发者常见问题解答
:我没有找到解决这个问题的方法。
值得一提的是,如果您使用
From the
Safari Developer FAQ
: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)这是一个有效的解决方案:
http://anantgarg.com /2010/02/18/cross-domain-cookies-in-safari/
Here is a solution which works:
http://anantgarg.com/2010/02/18/cross-domain-cookies-in-safari/
这可能并不适合所有人,但我遇到了这个问题,因为我从与 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.
工作方法 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
假设他们安装了闪存,就会有一些邪恶的伎俩。
我不确定它是否仍然有效,但 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.
发布到隐藏的
可以让您在 Safari 中绕过此限制 - http://gist.github.com/586182:
A post to a hidden
<iframe>
can allow you to by-pass this restriction in Safari -- http://gist.github.com/586182:2015 年有一个适当的解决方法可以解决此问题。假设有一个网站 y.com,其中包含带有网站 x.com 的 iframe。 x.com iframe 想要存储 cookie。 Safari 政策不允许这样做,但是 y.com 可以存储它。 因此 y.com 必须侦听来自 x.com 的消息,然后存储 cookie 本身。
当 x.com 需要存储 cookie 时,它必须向 y.com 发布一条消息:
如果您想读取 cookie,您也可以按照自己的方式向 iframe 发布消息。 或者您可以使用 javascript 将其作为参数包含在 x.com iframe url 中:
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.
When x.com needs to store the cookie, it must post a message to y.com:
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:
我们在工作中刚刚想出的一个解决方法是通过 window.open() 设置 cookie - 它可能不是您的最佳选择(因为您将打开一个丑陋的弹出窗口),但它对我们来说效果很好。 无论如何,我们必须打开一个弹出窗口才能进行 OAuth 身份验证。
因此,我们所做的要点是:
再次强调,全部无效解决方案,但它在我们的解决方案中有效。 希望这可以帮助。
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:
Again, not valid in all solutions, but it worked in ours. Hope this helps.
我知道这个问题相当老了,但这帮助我解决了 cookie 问题:在
设置 cookie 的页面上发布表单的想法。
I know this question is rather old, but this helped me to solve cookies problem:
The idea to make a form post on a page that sets your cookies.
*编辑*
据报道,此解决方法已在 WebKit 中关闭。
卢卡,
好吧,这个答案已经有两年了,但是...如果您将表单发布到隐藏的 iframe,则可以从 iframe 设置 cookie。 您可以通过创建一个表单来做到这一点:
然后在 Javascript 中,获取对表单的引用并调用提交:
您可以侦听 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:
Then in Javascript, get a reference to the form and call 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.
也许务实地创建并单击带有
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.)当我尝试部署一个使用 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".
请注意这一行:
在添加 http 之前我无法使其正常工作,即
Note this line:
I could not get this working until I added the http, i.e.
我找到了一个简单的解决方案。 您只需要第一次设置 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.
值得注意的是,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.
将此 JavaScript 放在发出跨域请求的页面上,http://example1.com/index.html:
然后在另一台服务器上创建一个文件,需要设置cookie,http://example2.com/activate .php:
这是如何工作的:
当http://example1.com/index.php首先访问index.html,检查浏览器是否是Safari,以及名称为“activated”的GET参数是否不存在。 如果满足这两个条件(这将在第一次访问 Safari 浏览器时发生),则浏览器将重定向到 http ://example2.com/activate.php 带有 GET 参数“callback”,包含附加有“activated”参数的调用 URL。
http://example2.com/activate.php 只是重定向回包含在GET 参数,“回调”。
当 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:
Then create a file on the other server, which needs to set cookies, http://example2.com/activate.php:
Here's how this works:
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.
http://example2.com/activate.php simply redirects back to the URL contained in the GET parameter, "callback".
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.
尝试类似的操作:
它可能会绕过 safari 的安全策略。
Try something like:
It may bypass safari's security policy.
这不是缺少类型属性让您烦恼吗?-)
It isn't the missing type-attribute thats annoying you ?-)