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

我在WebApp1的HttpResponse中设置了一个cookie。 如何从WebApp2中的HttpRequest读取相同的cookie ?

我知道这听起来很奇怪,因为cookie是特定于给定域的,我们不能从不同的域访问它们;不过我听说过跨域cookie,它可以在多个web应用程序之间共享。如何使用跨域cookie实现这一需求?

注意:我正在尝试使用J2EE web应用程序


没有所谓的跨域cookie。您可以在foo.example.com和bar.example.com之间共享cookie,但绝不可以在example.com和example2.com之间共享cookie,这是出于安全原因。


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

这是不可能的。例如访问example.com的cookie。


就像其他人说的,你不能分享cookie,但你可以这样做:

将所有cookie集中到一个域中,例如cookemaker .example 当用户向example.com发出请求时,您将他重定向到cookiemaker.example cookiemaker。Example将他重定向到example.com,并提供你需要的信息

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

最后,如果在每个请求中都这样做,对用户来说会非常讨厌,但如果只是第一个请求就不会。

但我认为没有别的办法了。


在nfriedly.com上有一个关于Facebook如何做到这一点的不错的概述

还有浏览器指纹识别,它与cookie不同,但作用类似,因为它可以帮助您以相当程度的确定性识别用户。Stack Overflow上有一篇文章提到了一种指纹识别方法


据我所知,cookie受到“同源”策略的限制。但是,使用CORS,您可以接收和使用“服务器B”cookie,在“服务器B”上从“服务器a”建立持久会话。

尽管,这需要在“服务器B”上设置一些头文件:

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

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

你可以在这里阅读:

http://www.html5rocks.com/en/tutorials/cors/

https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS


你可以使用隐形的iframe来获取cookie。假设有两个定义域,a。example和b。example。对于a.example域的index.html,可以添加(注意height=0 width=0):

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

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

下一件事是通过JavaScript在iframe中操作站点。如果不拥有第二个域,iframe内部的操作可能会成为一个挑战。但是,如果能够访问这两个域,在iframe的src中引用正确的网页应该会给出一个想要获得的cookie。


您可以尝试使用图像标记将cookie val推到另一个域。

在尝试这样做时,您的情况可能会有所不同,因为一些浏览器要求您在WebApp2域上有适当的P3P策略,否则浏览器将拒绝cookie。

如果你看plus.google.com p3p政策,你会看到他们的政策是:

CP="这不是P3P策略!更多信息请访问http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657。”

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

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


是的,从domain1获得cookie是完全可能的。domain2.example示例。我的社交网络的社交插件也遇到了同样的问题,经过一天的研究,我找到了解决方案。

首先,在服务器端,你需要有以下头文件:

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
}

做谷歌正在做的事情。创建一个PHP文件,在所有3个域上设置cookie。然后在主题将要设置的域上,创建一个HTML文件,该文件将加载在其他2个域上设置cookie的PHP文件。例子:

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

然后在body标签上添加一个onload回调。文档只会加载时,图像完全加载,即当cookie设置在其他2个域。Onload回调:

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

setcookie.php

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

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

现在在三个域中设置了cookie。


阅读Web Api中的Cookie

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

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

. config

包括UI原点和设置允许凭据为真

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

最聪明的解决办法就是效仿facebook的做法。当你访问任何域名时,facebook如何知道你是谁?其实很简单:

The Like button actually allows Facebook to track all visitors of the external site, no matter if they click it or not. Facebook can do that because they use an iframe to display the button. An iframe is something like an embedded browser window within a page. The difference between using an iframe and a simple image for the button is that the iframe contains a complete web page – from Facebook. There is not much going on on this page, except for the button and the information about how many people have liked the current page.

所以当你在cnn.com上看到一个“喜欢”按钮时,你实际上是在同时访问一个Facebook页面。这使得Facebook可以读取你电脑上的cookie,这些cookie是它在你上次登录Facebook时创建的。

每种浏览器的一个基本安全规则是,只有创建了cookie的网站以后才能读取它。这就是iframe的优势:它允许Facebook读取你的Facebook-cookie,即使你在访问另一个网站。这就是他们如何在cnn.com上认出你,并在那里展示你的朋友。

来源:

http://dorianroy.com/blog/2010/04/how-facebooks-like-button-works/ https://stackoverflow.com/a/8256920/715483


我已经创建了一个NPM模块,它允许你跨域共享本地存储的数据: https://www.npmjs.com/package/cookie-toss

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

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

使用域a中的域白名单,您可以确保只有您依赖的站点可以访问域a上的数据。

诀窍是在域A上的iframe中有能够识别正在请求的数据的代码。上面NPM模块中的README更深入地介绍了这个过程。

希望这能有所帮助!


不允许跨域cookie(即站点A不能在站点B上设置cookie)。

但是一旦站点a设置了cookie,您甚至可以在从站点B到站点a的请求中发送该cookie(即跨域请求):

来自不同域的XMLHttpRequest不能为自己的域设置cookie值,除非在发出请求之前将withCredentials设置为true。通过将withCredentials设置为true获得的第三方cookie仍然遵循同源策略,因此请求脚本无法通过文档访问。Cookie或响应头。

一定要做到以下几点:

When setting the cookie in a response The Set-Cookie response header includes SameSite=None if the requests are cross-site (note a request from www.example.dev to static.example.dev is actually a same-site request, and can use SameSite=Strict) The Set-Cookie response header should include the Secure attribute if served over HTTPS; as seen here and here When sending/receiving the cookie: The request is made with withCredentials: true, as mentioned in other answers here and here, including the original request whose response sets the cookie set in the first place For the fetch API, this attribute is credentials: 'include', vs withCredentials: true For jQuery's ajax method, note you may need to supply argument crossDomain: true The server response includes cross-origin headers like Access-Control-Allow-Origin, Access-Control-Allow-Credentials, Access-Control-Allow-Headers, and Access-Control-Allow-Methods As @nabrown points out: "Note that the "Access-Control-Allow-Origin" cannot be the wildcard (*) value if you use the withCredentials: true" (see @nabrown's comment which explains one workaround for this. In general: Your browser hasn't disabled 3rd-party cookies. (* see below)

你不需要的东西(使用上面的):

domain attribute in the Set-Cookie; you can choose a root domain (i.e. a.example.com can set a cookie with a domain value of example.com, but it's not necessary; the cookie will still be sent to a.example.com, even if sent from b.other-site.example For the cookie to be visible in Chrome Dev Tools, "Application" tab; if the value of cookie HttpOnly attribute is true, Chrome won't show you the cookie value in the Application tab (it should show the cookie value when set in the initial request, and sent in subsequent responses where withCredentials: true)

注意Cookie中“路径”和“站点”之间的区别。“path”与安全无关;“site”与安全相关:

path

服务器可以在set - cookie中设置Path属性,但这似乎与安全无关:

注意,该路径用于性能,而不是安全性。具有相同来源的网页仍然可以通过文档访问cookie。Cookie,即使路径不匹配。

site

根据example.dev文章,SameSite属性可以限制或允许跨站点cookie;但是什么是“站点”呢?

准确理解“site”在这里的意思是很有帮助的。网站是域名后缀和域名前面的部分的组合。例如,www.example.dev域是example.dev站点的一部分…

这意味着从www.example.dev到static.example.dev的请求是一个sameSite请求(url的唯一区别在于子域)。

公共后缀列表定义了这个,所以 它不只是像。com这样的顶级域名,还包括服务 像github.io

这意味着对your-project.github的请求。IO来自my-project.github。io,是一个跨站点请求(这些url在不同的域,因为github。IO是域后缀;你的项目和我的项目的领域是不同的;因此不同的网站)

这意味着public后缀的左边;是子域(但子域是主机的一部分;请看这个答案中的奖金回复)

WWW是www.example.dev的子域;与static.example.dev相同的站点 Your-project是Your-project .github.io中的域;单独的网站my-project.github.io

在这个URL https://www.example.com:8888/examples/index.html中,请记住以下部分:

“协议”:https:// “方案”:HTTPS “端口”:8888 “域名”也就是位置。主机名:www.example.com “域名后缀”即“顶级域名”(TLD): com domain:示例 “子域”:WWW(子域可以是单层的(如WWW),也可以是多层的(如foo。Bar in foo.bar.example.com) “站点”(即“跨站点”,如果另一个URL具有不同的“站点”值):example.com "site" = "域名" + "域名后缀" = example.com 路径:/examples/index.html

有用的链接:

URL的剖析 同源cookie策略和URL剖析 SameSite cookies解释道 安全的跨域cookie的HTTP |互联网服务和应用期刊|全文 draft-ietf-httpbis-rfc6265bis-03 Web安全1:同源和Cookie策略 Set-Cookie - HTTP | MDN

(小心;我在Chrome隐身标签测试我的功能;根据我的chrome://设置/cookies;我的设置是“Incognito屏蔽第三方cookie”,所以我不能在Incognito中测试跨站点cookie。)


因为很难做第三方cookie,也有些浏览器不允许这样做。

你可以尝试将它们存储在HTML5本地存储中,然后将它们与前端应用程序的每个请求一起发送。


除了@Ludovic(已批准的答案)的答案外,我们需要在获得set-cookies报头时检查另一个选项,

set-cookie: SESSIONID=60B2E91C53B976B444144063; Path=/dev/api/abc; HttpOnly

还要检查Path属性值。这应该与下面所示的API起始上下文路径相同

https://www.example.com/dev/api/abc/v1/users/123

或者在不确定上下文路径时使用下面的值

Path=/;

基于浏览器的存储主要有三种:

会话存储 本地存储 cookie存储


安全cookie -用于加密网站,以提供保护,免受来自黑客的任何可能威胁。 访问cookie - document.cookie。这意味着这个cookie是公开的,可以通过跨站点脚本来利用。保存的cookie值可以通过浏览器控制台看到。

作为预防措施,您应该总是尝试使用JavaScript使您的cookie在客户端不可访问。

HTTPonly - ensures that a cookie is not accessible using the JavaScript code. This is the most crucial form of protection against cross-scripting attacks. A secure attribute - ensures that the browser will reject cookies unless the connection happens over HTTPS. sameSite attribute improves cookie security and avoids privacy leaks. sameSite=Lax - It is set to Lax (sameSite = Lax) meaning a cookie is only set when the domain in the URL of the browser matches the domain of the cookie, thus eliminating third party’s domains. This will restrict cross-site sharing even between different domains that the same publisher owns. we need to include SameSite=None to avoid the new default of Lax:

注意:有一个规范草案要求当SameSite属性被设置为“none”时Secure属性被设置为true。一些web浏览器或其他客户端可能采用此规范。

使用include作为{withCredentials: true}必须包含来自前端的请求的所有cookie。

const data = { email: 'youremailaddress@gmail.com' , password: '1234' };
const response = await axios.post('www.yourapi.com/login', data , { withCredentials: true });

Cookie只能在安全的HTTPS连接上被接受。为了使其工作,我们必须将web应用程序移动到HTTPS。

在express.js

res.cookie('token', token, {
      maxAge: 1000 * 60 * 60 * 24, // would expire after (for 15 minutes  1000 * 60 * 15 ) 15 minutes
      httpOnly: true, // The cookie only accessible by the web server
      sameSite: 'none',
      secure: true, // Marks the cookie to be used with HTTPS only.
    });

参考文献1,参考文献2