跨域Cookie


246

我在两个不同的域中有两个webapps WebApp1和WebApp2。

  1. 我正在HttpResponse中的WebApp1中设置cookie。
  2. 如何从WebApp2中的HttpRequest读取相同的cookie?

我知道这听起来很奇怪,因为Cookie是特定于给定域的,并且我们无法从不同域访问它们。但是,我听说过可以在多个Web应用程序之间共享的跨域Cookie。如何使用跨域Cookie来实现此要求?

注意:我正在使用J2EE webapps尝试此操作

Answers:


129

是的,绝对可以通过domain2.com从domain1.com获取cookie。对于我的社交网络的社交插件,我遇到了同样的问题,经过一天的研究,我找到了解决方案。

首先,在服务器端,您需要具有以下标头:

header("Access-Control-Allow-Origin: http://origin.domain:port");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Methods: GET, POST");
header("Access-Control-Allow-Headers: Content-Type, *");

在PHP文件中,您可以使用 $_COOKIE[name]

第二,在客户端:

在您的ajax请求中,您需要包括2个参数

crossDomain: true
xhrFields: { withCredentials: true }

例:

type: "get",
url: link,
crossDomain: true,
dataType: 'json',
xhrFields: {
  withCredentials: true
}

6
或者,如果您不想按来源进行过滤,只需使用$ _SERVER ['HTTP_ORIGIN']而不是*
Joel Teply 2015年

1
这是唯一对我有用的东西。此外,*不被接受为来源,因此需要@Joel Teply的提示。
孰料

4
如果禁用了第三方Cookie(在某些浏览器情况下自动启用),则此功能将无效。有关更多信息,请参见blog.zok.pw/web/2015/10/21/3rd-party-cookies-in-practiceallannienhuis.com/archives/2013/11/03/…
robocat '16

4
不要使用Joel的技巧,因为它本质上与将其设置为“ *”相同,因为它可能会打开细微的安全漏洞,因此不鼓励使用,请参阅stackoverflow.com/questions/12001269/…–
rogerdpack

5
在哪个域的服务器端?
尼克·曼宁'18

127

就像其他人说的那样,您无法共享Cookie,但是您可以执行以下操作:

  1. 假设将cookie集中在一个域中
  2. 当用户向example.com发出请求时,您会将其重定向到cookiemaker.com
  3. cookiemaker.com使用您需要的信息将他重定向到example.com

当然,它不是完全安全的,您必须在应用之间创建某种内部协议才能做到这一点。

最后,如果您在每个请求中都执行类似的操作,那么对于用户来说将是非常烦人的,但是如果这只是第一个请求,则不会如此。

但我认为别无他法...


44
如果没有其他方法,那么StackExchange / OpenID如何工作?
霍肯,2012年

60
@Hawken StackExchange / OpenID遵循与上述相同的过程。您将被引导到另一个站点(SO> SX),确认您的身份,然后使用所需的信息被引导回SO。尽管Wikipedia更清楚地说明了OpenID规范,但解释更多。
Nick Q.

1
实际上,所有用户都已登录cookiemaker.com。并通过一条特殊且安全的消息将用户重定向到其他站点,以验证他们是否已登录以及他们是谁。如何实施它取决于您,这样做的方式有很多。也许您可以使用:jwt.io
alcuadrado 2015年

8
@ Andrew_1510 cookiebaker会更好;-)
理查德·特纳

1
是带有图像标签的帖子,是一个更好的解决方案吗?
shaijut

70

据我所知,cookie受“相同来源”政策的限制。但是,通过CORS,您可以接收和使用“服务器B” cookie从“服务器B”上的“服务器A”建立持久会话。

虽然,这需要“服务器B”上的一些标头:

Access-Control-Allow-Origin: http://server-a.domain.com
Access-Control-Allow-Credentials: true

你将需要发送的标志“ withCredentials上的所有“服务器A”请求”(例如:xhr.withCredentials = true;

你可以在这里读到它:

http://www.html5rocks.com/zh-CN/tutorials/cors/

https://developer.mozilla.org/zh-CN/docs/HTTP/Access_control_CORS


10
这不适用于某些用户,因为如果禁用了第三方cookie(例如,默认情况下为Safari)(例如Mozilla设置),则CORS cookie将不起作用。Google的更多示例以及有关Facebook为什么不使用第三方Cookie的文章。
robocat

1
堆栈交换/ openID是否使用CORS?
RayLoveless

1
FWIW我刚刚用凭证XHR测试了一个普通的CORS,它可以在FF / Safari / Chrome上运行...尽管我毫不怀疑facebook / google使用了更复杂的方案
rogerdpack

29

没有跨域Cookie。您可以在foo.example.combar.example.com之间共享一个Cookie ,但不能在example.com和之间共享一个cookie example2.com,这是出于安全原因。


1
嗨,谢谢您的答复,您能在配置部分,如何在j2ee环境中创建/配置域和子域吗?
SundarJavaDeveloper

1
这是一个更适合serverfault.com的问题,在这里您将获得该领域专家的解答。
达林·迪米特洛夫

嗨,我尝试过两个webapps WebApp.domain.com ==>在这里我以如下方式添加cookie:Cookie cookie = new Cookie(“ namedCookie”,“ test”); cookie.setDomain(“。domain.com”); response.addCookie(cookie); WebApp1.domain.com ==>在此,我尝试按以下方式访问Cookie,但无法访问Cookie [] cks = request.getCookies();。for(int i = 0; i <cks.length; i ++){out.print(“找到Cookie” + cks [i] .getValue()); 对此有任何想法吗?
SundarJavaDeveloper

2
经常反复,但不是真的,看到我的回答下面或这里stackoverflow.com/questions/16186645/...
拉斐尔Jeger

4
如何在foo.example.com和之间共享Cookie bar.example.com
Jeff Tian

24

最明智的解决方案是遵循Facebook的做法。当您访问任何域时,facebook如何知道您是谁?实际上非常简单

“喜欢”按钮实际上允许Facebook跟踪外部网站的所有访问者,无论他们是否单击它。Facebook之所以可以这样做是因为他们使用iframe来显示按钮。iframe类似于页面内的嵌入式浏览器窗口。使用iframe和按钮的简单图片之间的区别在于iframe包含来自Facebook的完整网页。除了按钮和有关有多少人喜欢当前页面的信息之外,此页面上没有什么其他操作。

因此,当您在cnn.com上看到一个点赞按钮时,您实际上是在同时访问一个Facebook页面。这样一来,Facebook便可以读取您计算机上的cookie,该cookie是您上次登录Facebook时创建的。

每个浏览器中的基本安全规则是,只有创建Cookie的网站才能稍后读取它。这就是iframe的优势:即使您访问其他网站,它也可以使Facebook读取您的Facebook cookie。这就是他们在cnn.com上识别您并在其中显示您的朋友的方式。

资源:


6
我认为iframe很少会被归类为做任何事情的最好或最聪明的方法..但这是最简单的。
奥伦(Orun)

13

做Google在做什么。创建一个在所有3个域上设置cookie的PHP文件。然后在要设置主题的域上,创建一个HTML文件,该文件将加载在其他2个域上设置cookie的PHP文件。例:

<html>
   <head></head>
   <body>
      <p>Please wait.....</p>
      <img src="http://domain2.com/setcookie.php?theme=whateveryourthemehere" />
      <img src="http://domain3.com/setcookie.php?theme=whateveryourthemehere" />
   </body>
</html>

然后在body标签上添加onload回调。仅在完全加载图像(即在其他2个域上设置cookie时)才加载文档。上载回调:

<head>
   <script>
   function loadComplete(){
      window.location="http://domain1.com";//URL of domain1
   }
   </script>
</head>
<body onload="loadComplete()">

setcookie.php

我们使用如下PHP文件在其他域上设置cookie:

<?php
if(isset($_GET['theme'])){
   setcookie("theme", $_GET['theme'], time()+3600);
}
?>

现在,在三个域上设置了cookie。


2
如果启用了“阻止第三方Cookie”功能,则此功能无效。
詹斯

11

您不能跨域共享Cookie。但是,您可以允许所有子域都可以访问。要允许的所有子域example.com访问,请将域设置为.example.com

不过,无法授予otherexample.comexample.com的Cookie的访问权限。


27
.google.com然后浏览到YouTube时cookie 如何显示?
霍肯,2012年

20
Google Analytics(分析)标签。这些Cookie来自google.com,而不来自youtube.com。
Entendu 2013年

8

您可以尝试使用image标签将cookie val推送到另一个域。

尝试执行此操作时,您的里程可能会有所不同,因为某些浏览器要求您在WebApp2域上具有适当的P3P策略,否则浏览器将拒绝cookie。

如果您查看plus.google.com p3p政策,您会发现他们的政策是:

CP =“这不是P3P政策!有关更多信息,请参见http://www.google.com/support/accounts/bin/answer.py?hl=zh_CN&answer=151657。”

这是他们针对这些跨域请求的+1按钮使用的策略。

另一个警告是,如果您使用的是https,请确保图像标记也指向https地址,否则将不会设置cookie。


2
介意详细一点吗?
2014年


1

可以使用不可见的iframe来获取Cookie。假设有两个域,即a.com和b.com。对于域名a.com的index.html,可以添加(注意height = 0 width = 0):

<iframe height="0" id="iframe" src="http://b.com" width="0"></iframe>

这样,假设http://b.com设置了cookie ,您的网站将获得b.com cookie。

接下来的事情是通过JavaScript在iframe中操作网站。如果一个人不拥有第二个域,则iframe中的操作可能会成为一个挑战。但是,如果可以同时访问这两个域,则在iframe的src上引用正确的网页应该会给cookie一个人想要的东西。


5
只是警告:Safari的iframe中的Cookie存在一些严重问题。他们显然不能跨域工作。
mvds

1
function GetOrder(status, filter) {
    var isValid = true; //isValidGuid(customerId);
    if (isValid) {
        var refundhtmlstr = '';
        //varsURL = ApiPath + '/api/Orders/Customer/' + customerId + '?status=' + status + '&filter=' + filter;
        varsURL = ApiPath + '/api/Orders/Customer?status=' + status + '&filter=' + filter;
        $.ajax({
            type: "GET",
            //url: ApiPath + '/api/Orders/Customer/' + customerId + '?status=' + status + '&filter=' + filter,
            url: ApiPath + '/api/Orders/Customer?status=' + status + '&filter=' + filter,
            dataType: "json",
            crossDomain: true,
            xhrFields: {
                withCredentials: true
            },
            success: function (data) {
                var htmlStr = '';
                if (data == null || data.Count === 0) {
                    htmlStr = '<div class="card"><div class="card-header">Bu kriterlere uygun sipariş bulunamadı.</div></div>';
                }
                else {
                    $('#ReturnPolicyBtnUrl').attr('href', data.ReturnPolicyBtnUrl);
                    var groupedData = data.OrderDto.sort(function (x, y) {
                        return new Date(y.OrderDate) - new Date(x.OrderDate);
                    });
                    groupedData = _.groupBy(data.OrderDto, function (d) { return toMonthStr(d.OrderDate) });
                    localStorage['orderData'] = JSON.stringify(data.OrderDto);

                    $.each(groupedData, function (key, val) {

                        var sortedData = groupedData[key].sort(function (x, y) {
                            return new Date(y.OrderDate) - new Date(x.OrderDate);
                        });
                        htmlStr += '<div class="card-header">' + key + '</div>';
                        $.each(sortedData, function (keyitem, valitem) {
                            //Date Convertions
                            if (valitem.StatusDesc != null) {
                                valitem.StatusDesc = valitem.StatusDesc;
                            }

                            var date = valitem.OrderDate;
                            date = date.substring(0, 10).split('-');
                            date = date[2] + '.' + date[1] + '.' + date[0];
                            htmlStr += '<div class="col-lg-12 col-md-12 col-xs-12 col-sm-12 card-item clearfix ">' +
                        //'<div class="card-item-head"><span class="order-head">Sipariş No: <a href="ViewOrderDetails.html?CustomerId=' + customerId + '&OrderNo=' + valitem.OrderNumber + '" >' + valitem.OrderNumber + '</a></span><span class="order-date">' + date + '</span></div>' +
                        '<div class="card-item-head"><span class="order-head">Sipariş No: <a href="ViewOrderDetails.html?OrderNo=' + valitem.OrderNumber + '" >' + valitem.OrderNumber + '</a></span><span class="order-date">' + date + '</span></div>' +
                        '<div class="card-item-head-desc">' + valitem.StatusDesc + '</div>' +
                        '<div class="card-item-body">' +
                            '<div class="slider responsive">';
                            var i = 0;
                            $.each(valitem.ItemList, function (keylineitem, vallineitem) {
                                var imageUrl = vallineitem.ProductImageUrl.replace('{size}', 200);
                                htmlStr += '<div><img src="' + imageUrl + '" alt="' + vallineitem.ProductName + '"><span class="img-desc">' + ProductNameStr(vallineitem.ProductName) + '</span></div>';
                                i++;
                            });
                            htmlStr += '</div>' +
                        '</div>' +
                    '</div>';
                        });
                    });

                    $.each(data.OrderDto, function (key, value) {
                        if (value.IsSAPMigrationflag === true) {
                            refundhtmlstr = '<div class="notify-reason"><span class="note"><B>Notification : </B> Geçmiş siparişleriniz yükleniyor.  Lütfen kısa bir süre sonra tekrar kontrol ediniz. Teşekkürler. </span></div>';
                        }
                    });
                }
                $('#orders').html(htmlStr);
                $("#notification").html(refundhtmlstr);
                ApplySlide();
            },
            error: function () {
                console.log("System Failure");
            }
        });
    }
}

Web.config

包括UI原点,并将Allow Crentials设置为true

<httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="http://burada.com" />
        <add name="Access-Control-Allow-Headers" value="Content-Type" />
        <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
        <add name="Access-Control-Allow-Credentials" value="true" />
      </customHeaders>
    </httpProtocol>

1

我创建了一个NPM模块,该模块可让您跨域共享本地存储的数据:https//www.npmjs.com/package/cookie-toss

通过使用托管在域A上的iframe,您可以将所有用户数据存储在域A上,并通过将请求发布到域A iframe来引用这些数据。

因此,域B,C等可以注入iframe并向其发布请求以存储和访问所需数据。域A成为所有共享数据的中心。

使用域A内的域白名单,可以确保只有从属站点可以访问域A上的数据。

诀窍是将代码放在域A的iframe中,该代码能够识别正在请求的数据。上述NPM模块中的自述文件将更深入地介绍该过程。

希望这可以帮助!


-4

CookieWeb Api

var cookie = actionContext.Request.Headers.GetCookies("newhbsslv1");


                    Logger.Log("Cookie  " + cookie, LoggerLevel.Info);
                    Logger.Log("Cookie count  " + cookie.Count, LoggerLevel.Info);

                    if (cookie != null && cookie.Count > 0)
                    {
                        Logger.Log("Befor For  " , LoggerLevel.Info);
                        foreach (var perCookie in cookie[0].Cookies)
                        {
                            Logger.Log("perCookie  " + perCookie, LoggerLevel.Info);

                            if (perCookie.Name == "newhbsslv1")
                            {
                                strToken = perCookie.Value;
                            }
                        }
                    }

这不能解决在两个不同域上使用的OP问题
Niklas Wulff '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.