如何为另一个域名设置cookie

229
假设我有一个名为 a.com 的网站,当加载该网站的特定页面(例如页面链接)时,我想为另一个名为b.com 的站点设置一个 cookie,然后将用户重定向到 b.com。我的意思是,在加载 a.com/link 时,我想要为 b.com 设置一个 cookie 并将用户重定向到 b.com
我已经测试过了,浏览器实际上从 a.com/link 接收到了 cookie,但在重定向请求到 b.com 时并没有发送该 cookie。这是正常的吗?
我们可以为其他域设置 cookies 吗?

请注意,如果您使用URL参数在b.com上设置cookie,则任何人都可以从任何网站强制设置b.com上的任何cookie值。 - Julien
2
使用一个设置了 cookie 的 b.com 的 iFrame ;) - Jaquarh
11个回答

168

你无法为另一个域名设置cookie。允许这样做将会产生巨大的安全漏洞。

你需要让b.com设置cookie。如果a.com重定向用户到b.com/setcookie.php?c=value

setcookie脚本可以包含以下内容来设置cookie并重定向到b.com上的正确页面。

<?php
    setcookie('a', $_GET['c']);
    header("Location: b.com/landingpage.php");
?>

3
@Coder,setcookie 函数将会导致一个 cookie 头从 b.com 发送到浏览器。a.com 无法从 b.com 发送一个 cookie 头。我会尽力让译文更通俗易懂,但不改变原意。 - qbert220
7
最好在答案中注意到,尽管它可行,但这是不安全的。 - Roy Ling
3
YouTube 通过读取 Gmail 创建的 cookies 来显示用户在 YouTube 上的账户,但这并不能否定你所说的话。 - TAHA SULTAN TEMURI
3
@TAHA,你的谷歌账户数据并不存储在cookie中。该cookie只包含一个指向谷歌服务器上的数据库行的密钥。YouTube使用oAuth以安全的方式检索cookie的值,然后使用该密钥从数据库中检索您的数据。 - user10398534
3
如果这种方法不安全,那么首选的方法是什么? - lowcrawler
显示剩余7条评论

59
与顶部答案类似,但是不要重定向到页面并返回,这会导致糟糕的用户体验,您可以在A域上设置一个图像。

与顶部答案类似,但是不要重定向到页面并返回,这会导致糟糕的用户体验,您可以在A域上设置一个图像。

<img src="http://www.example.com/cookie.php?val=123" style="display:none;">

然后在域名B,也就是example.com的cookie.php文件中,你将会看到以下代码:

<?php
    setcookie('a', $_GET['val']);
?>

Subin致敬。


2
不错的黑客技巧... :) - yakya
38
请注意,这可能是一个非常糟糕的想法。你正在绕过非常有意义的Cookie保护措施,基本上是让任何人发送经过精心设计的GET请求来将该Cookie设置为他们想要的任何值。我不知道你会用那个Cookie做什么,但我希望它不涉及银行余额。 - Scott Stafford
1
我可以向您保证,这并没有涉及到银行余额。但是说得好 :) - Jonathan
3
如果在这种情况下,每个人都可以使用自己的参数调用该域名,则可以通过添加另一个参数来增加安全性。使用数据和额外盐创建一个哈希,并将其作为参数传递。在您的cookie.php中,只需通过重新创建令牌并比较它们来验证$_GET ['val']中的数据即可。 - Seba M
2
如果你这样发送GET请求,你也可以使用AJAX。 - user10398534
显示剩余2条评论

20

可能你可以使用 Iframe 来实现。Facebook可能使用了这种技术。你可以在 这里 阅读更多信息。Stackoverflow 使用类似的技术,但是使用 HTML5 本地存储,更多信息请参见他们的 博客


1
iframe 对我的解决方案非常有效,只需像普通的 get 请求一样在 URL 中包含值,并从服务器响应 cookie 值即可。 - Joel Davis
请注意,您必须正确配置Access-Control-Allow-Origin才能使其正常工作。 - user10398534

12
你无法直接设置该Cookie,这将带来严重的安全风险。虽然你可以指定域属性,但规范说:“除非域属性指定了一个包含原始服务器的cookie范围,否则用户代理将拒绝cookie。”由于原始服务器是a.com,不包括b.com,因此无法设置它。你需要让b.com设置该cookie。你可以通过HTTP重定向到b.com并返回来实现此目的。

3
@Timberman — 这个问题涉及到运行在网站上的 JavaScript,而不是开发者工具或明确安装的扩展程序。这将带来安全风险,因为任何访问 evil-hack.com 的人都可能在 their-favourite-website.com 上设置一个 cookie,从而更改他们在该网站上的偏好设置。 - Quentin
我理解,但它怎么会成为安全风险呢?我相当确定它与安全无关。 - Timberman
@Timberman — 如果你看不出攻击者网站改变你对完全不同的网站的偏好存在问题,那么我就不知道该如何更清楚地解释了。 - Quentin
我看到了问题,但我不明白它如何成为安全风险。我同意你的观点,即JavaScript不应该能够为不同的域设置cookie,但如果它能够这样做,那么它怎么会成为安全问题呢? - Timberman
@Timberman,信息安全的三个主要属性之一是完整性(https://www.nccoe.nist.gov/publication/1800-25/VolA/index.html)。未经用户同意就能够从另一个站点更改站点内容/配置的能力可能被视为对完整性的攻击,从而构成安全问题。归根结底,正如Quentin所举的例子,`evil-hack.com`将在您不知情的情况下向`their-favourite-website.com`注入信息。风险和影响评估是另一回事。 - lexotero
显示剩余2条评论

9

如果您拥有的是a.my-company.comb.my-company.com而不是只有a.comb.com,您可以为.my-company.com域发出一个cookie-它将被接受并发送到这两个域。


1
能否在a.my-company.com为b.my-company.com创建一个cookie? - mahesh kajale
2
除非my-company.com在公共后缀黑洞列表中,否则浏览器将默默忽略所有设置cookie的尝试!:'-( - Michael
你说得没错,但如果事情发生了,我们必须找到解决方案。这不是这个问题的解决方案。不要给建议,只要提供解决方案。 - horoyoi o

6

无法为另一个域设置cookie。

如果您想将数据传递到另一个域,可以将其编码到URL中。

a.com  ->  b.com/redirect?info=some+info (and set cookie) -> b.com/other+page

7
从 URL 设置会话 Cookie 存在安全风险。URL 通常会被记录下来,这将允许攻击者窃取用户的会话。 - Dane Macaulay

6
请参见RFC6265

用户代理将拒绝cookie,除非域属性指定的范围包括源服务器。例如,用户代理将从foo.example.com接受具有“example.com”或“foo.example.com”域属性的cookie,但是用户代理不会接受具有“bar.example.com”或“baz.foo.example.com”域属性的cookie。

注意:出于安全原因,许多用户代理被配置为拒绝与“公共后缀”相对应的域属性。例如,某些用户代理将拒绝“com”或“co.uk”的域属性。(请参见第5.3节了解更多信息。)

但上述图片/iframe的解决方法可行,尽管由于其不安全性,不建议使用。


3
你不能这样做,但是...如果你拥有两个页面的话...
1) 你可以通过查询参数发送数据(http://siteB.com/?key=value)
2) 你可以在网站A中创建一个网站B的iframe,并且可以从一个地方向另一个地方发送post消息。由于网站B是网站B cookie的所有者,因此它将能够通过处理正确的post消息设置所需的任何值。(你应该防止其他不需要的发送者向你发送消息!这取决于你和你决定使用的机制来防止发生这种情况)

2

以下是我所使用的方法。请注意,此cookie在传输时(http)是明文的,因此不安全。我不会将其用于需要安全性的任何事情。

  1. 站点A生成一个令牌并将其作为URL参数传递给站点B。
  2. 站点B接收该令牌并将其设置为会话cookie。

您可以添加加密/签名以使其更加安全。请在如何正确执行此操作方面进行研究。


是的,我曾考虑过这样做,但是据说在URL中传递令牌是不安全的,因为它们会绕过SSL并存储在日志和浏览器历史记录中。 - Barney Szabolcs
正如我所评论的,这可以变得更安全。如果A站点和B站点共享加密密钥,则第三方无法读取它。仅进行加密是不够的,您可能需要包括一个随机数来防止各种中间人攻击。这样可以确保安全,但您仍需要做更多的功课。毕竟,https是建立在http之上的。 - thebiggestlebowski
明白了。所以你先进行一些ajax握手,然后将现在已经安全的URL传递给open方法。 - Barney Szabolcs
如果A -> B调用是https,则网络调用通过电线是安全的,因为URL已加密。 您可以通过加密进一步保护数据。 A和B需要共享加密密钥。 A加密URL令牌。 它被加密记录在浏览器中,这意味着没有人可以读取它,因为解密密钥在服务器上而不是浏览器中。 理想情况下,您应该将加密信息作为http头传递,以便它不会被记录或出现在历史记录中。 阅读有关生成OAuth令牌的文章,以获取更多保护(数字签名和哈希以检测篡改,随机数以防止中间人攻击等)的想法。 - thebiggestlebowski
我明白了,这很有道理,谢谢。顺便说一下,我喜欢你在Stackoverflow上的名字:)《大混乱》是我最喜欢的电影之一! - Barney Szabolcs
1
他也是我最喜欢的电影角色。很高兴你也喜欢! - thebiggestlebowski

2

从A发送POST请求。POST请求只在服务器端存在,客户端无法访问。

您可以使用CURL(建议在服务器端)或隐藏的method="POST"表单(客户端)从a.comb.com发送POST请求。如果您选择后者,可能需要混淆JavaScript代码,以便用户无法理解算法并干扰它。

b.com上创建网关以设置cookie:

<?php
    if (isset($_POST['data']) {
        setcookie('a', $_POST['data']);
        header("Location: b.com/landingpage");
    }
?>

如果您想进一步增强安全性,请在两个端点(a.comb.com)上实现一个加密(在 a.com 上)和解密(在 b.com 上)数据的功能,使用密码学密码。
如果您正在尝试执行必须绝对安全的操作(例如传输登录会话),请尝试使用 oAuth 或从 https://api.cloudianos.com/docs#v2/auth 获取一些灵感。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接