Междоменные куки

247

У меня есть два веб-приложения WebApp1 и WebApp2 в двух разных доменах.

  1. Я устанавливаю cookie в WebApp1 в HttpResponse.
  2. Как прочитать тот же cookie из HttpRequest в WebApp2?

Я знаю, это звучит странно, потому что файлы cookie относятся к конкретному домену, и мы не можем получить к ним доступ из разных доменов; Однако я слышал о файлах cookie CROSS-DOMAIN, которые могут использоваться несколькими веб-приложениями. Как реализовать это требование с помощью файлов cookie CROSS-DOMAIN?

Примечание: я пытаюсь это сделать с помощью веб-приложений J2EE

SundarJavaDeveloper
источник

Ответы:

130

Да, это абсолютно возможно получить cookie от domain1.com на domain2.com. У меня была такая же проблема с социальным плагином в моей социальной сети, и после дня исследований я нашел решение.

Во-первых, на стороне сервера вы должны иметь следующие заголовки:

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'] вместо *
Джоэль Тепли
1
Это единственное, что сработало для меня. Кроме того, * не было принято в качестве источника, так что совет @Joel Teply необходим.
предположил
4
Это не будет работать, если сторонние куки отключены (автоматически для некоторых ситуаций браузера). См. Blog.zok.pw/web/2015/10/21/3rd-party-cookies-in-practice и allannienhuis.com/archives/2013/11/03/… для получения дополнительной информации.
Робокат
4
Не используйте кончик Джоэла, потому что «в сущности» то же самое, установив его на «*» , который может открыть тонкие дыры в безопасности , так отвергающих , см stackoverflow.com/questions/12001269/...
rogerdpack
5
на стороне сервера какого домена?
Ник Мэннинг
127

Как говорят другие люди, вы не можете делиться файлами cookie, но вы можете сделать что-то вроде этого:

  1. централизовать все куки в одном домене, скажем cookiemaker.com
  2. когда пользователь отправляет запрос на example.com, вы перенаправляете его на cookiemaker.com
  3. cookiemaker.com перенаправляет его обратно на example.com с необходимой информацией

Конечно, это не совсем безопасно, и для этого вам нужно создать какой-то внутренний протокол между приложениями.

Наконец, пользователю будет очень неприятно, если вы будете делать что-то подобное в каждом запросе, но не в том случае, если это только первый шаг.

Но я думаю, что нет другого пути ...

alcuadrado
источник
44
Если другого пути нет, то как работает StackExchange / OpenID?
Hawken
60
@Hawken StackExchange / OpenID следует тому же процессу, что и описанный выше. Вы перенаправлены на другой сайт (SO> SX), подтвердите свою личность, а затем перенаправлены обратно в SO с необходимой вам информацией. Спецификация OpenID объясняет больше, хотя Википедия делает это более просто .
Ник В.
1
Все пользователи вошли в cookiemaker.com на самом деле. И он перенаправляет пользователя на разные сайты с помощью специального и безопасного сообщения, которое проверяет, вошли ли они в систему и кто они. Как реализовать это зависит от вас, есть бесконечные способы сделать это. Может быть, вы можете использовать это: jwt.io
alcuadrado
8
@ Andrew_1510 cookiebakerбыло бы лучше ;-)
Ричард Тернер
1
Вот пост с тегом изображения, это лучшее решение ?
Shaijut
70

Насколько я знаю, cookie-файлы ограничены политикой «одного и того же происхождения». Однако с помощью CORS вы можете получать и использовать файлы «Сервер B» для установки постоянного сеанса с «Сервер A» на «Сервер B».

Хотя для этого требуются некоторые заголовки на «сервере B»:

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

И вам нужно будет отправить флаг « withCredentials » на все запросы «Сервер A» (например: xhr.withCredentials = true;)

Вы можете прочитать об этом здесь:

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

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

Vitae Aliquam
источник
11
Это не будет работать для некоторых пользователей, потому что файлы cookie CORS не будут работать, если сторонние файлы cookie отключены, например, Safari по умолчанию, например, настройки Mozilla . Google больше примеров и статья о том, почему Facebook не использует сторонние куки.
Робокат
1
Использует ли стек для обмена / openID CORS?
RayLoveless
1
FWIW Я только что протестировал нормальный CORS с Credentials XHR, и он работал на FF / Safari / Chrome ... хотя я не сомневаюсь, что facebook / google используют более сложные схемы
rogerdpack
30

Нет такой вещи как междоменные куки. Вы могли бы поделиться печеньем между foo.example.comи , bar.example.comно никогда между example.comи example2.comи это по соображениям безопасности.

Дарин димитров
источник
1
Привет спасибо за ответ, можете ли вы добавить больше ясности в части конфигурации, как создать / настроить домен и поддомен в среде j2ee ???
SundarJavaDeveloper
1
Этот вопрос больше подходит для serverfault.com, где вы получите ответы от экспертов в этой области.
Дарин Димитров
Привет, я попытался иметь два веб-приложения. WebApp.domain.com ==> здесь я добавляю cookie в respose следующим образом: Cookie cookie = new Cookie ("namedCookie", "test"); cookie.setDomain ( "domain.com."); response.addCookie (печенья); WebApp1.domain.com ==> Здесь я попытался получить доступ к cookie следующим образом, но не смог получить доступ к Cookie [] cks = request.getCookies (); for (int i = 0; i <cks.length; i ++) {out.print ("cookie cookie найдено" + cks [i] .getValue ()); } Есть идеи по этому поводу?
SundarJavaDeveloper
2
часто повторяется, но не соответствует действительности, см. мой ответ ниже или здесь stackoverflow.com/questions/16186645/…
Рафаэль Джегер
4
Как поделиться куки между foo.example.comи bar.example.com?
Джефф Тиан
24

Самое разумное решение - следовать по пути Facebook. Как Facebook узнает, кто вы, когда посещаете какой-либо домен? Это на самом деле очень просто :

Кнопка «Мне нравится» фактически позволяет Facebook отслеживать всех посетителей внешнего сайта, независимо от того, нажимают они на них или нет. Facebook может сделать это, потому что они используют iframe для отображения кнопки. Iframe - это что-то вроде встроенного окна браузера на странице. Разница между использованием iframe и простого изображения для кнопки заключается в том, что iframe содержит полную веб-страницу - из Facebook . На этой странице ничего особенного не происходит, кроме кнопки и информации о том, как много людей понравилась текущая страница.

Поэтому, когда вы видите кнопку «Мне нравится» на cnn.com, вы одновременно посещаете страницу Facebook. Это позволяет Facebook читать файл cookie на вашем компьютере, который был создан при последнем входе в Facebook.

Основное правило безопасности в каждом браузере заключается в том, что только веб-сайт, создавший cookie-файл, может прочитать его позже. И это является преимуществом iframe: он позволяет Facebook читать ваш файл cookie Facebook, даже когда вы посещаете другой веб-сайт. Вот как они узнают вас на cnn.com и показывают там ваших друзей.

Источник:

Мортеза Шахриари Ниа
источник
6
Я думаю, что iframe редко классифицируют как лучший или самый умный способ сделать что-либо ... но это самый простой.
Орун
13

Делай то, что делает Google. Создайте файл PHP, который устанавливает cookie на всех 3 доменах. Затем в домене, где будет установлена ​​тема, создайте файл HTML, который будет загружать файл PHP, который устанавливает cookie в двух других доменах. Пример:

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

Затем добавьте обратный вызов onload для тега body. Документ будет загружаться только тогда, когда изображения полностью загружаются, то есть когда файлы cookie установлены на двух других доменах. Onload Callback:

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

setcookie.php

Мы устанавливаем файлы cookie для других доменов, используя PHP-файл, например так:

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

Теперь куки установлены на трех доменах.

Хоссейн Хадемян
источник
2
Это не работает, если включена функция «Блокировать сторонние файлы cookie».
Йенс
11

Вы не можете делиться файлами cookie между доменами Однако вы можете разрешить доступ ко всем поддоменам. Чтобы разрешить example.comдоступ всем поддоменам , установите для этого домена значение .example.com.

Однако невозможно предоставить otherexample.comдоступ к example.comфайлам cookie.

Даниэль Эгеберг
источник
27
почему .google.comфайлы cookie отображаются при просмотре на YouTube?
Хоукен
20
Теги Google Analytics. Эти файлы cookie приходят с google.com, а не с youtube.com.
Entendu
8

Вы можете попытаться отправить cookie val в другой домен, используя тег изображения.

Ваш пробег может варьироваться при попытке сделать это, потому что некоторые браузеры требуют, чтобы у вас была правильная политика P3P в домене WebApp2, иначе браузер отклонит cookie.

Если вы посмотрите на политику p.gp plus.google.com, то увидите, что их политика:

CP = "Это не политика P3P! Подробнее читайте в http://www.google.com/support/accounts/bin/answer.py?hl=ru&answer=151657 ".

это политика, которую они используют для своих кнопок +1 к этим междоменным запросам.

Еще одно предупреждение: если вы находитесь на https, убедитесь, что тег изображения указывает на адрес https, иначе файлы cookie не будут установлены.

Брайан Фохт
источник
2
Хотите немного проработать?
частые
5

Достаточный обзор того, как Facebook делает это здесь, на nfriedly.com

Существует также «Отпечаток пальца» в браузере, который не совпадает с файлом cookie, но выполняет аналогичную функцию, поскольку помогает идентифицировать пользователя с достаточной степенью уверенности. Здесь есть пост о переполнении стека, который ссылается на один метод снятия отпечатков

byZero
источник
1

Для получения файлов cookie можно использовать невидимые фреймы. Допустим, есть два домена, a.com и b.com. Для index.html домена a.com можно добавить (высота уведомления = 0 ширина = 0):

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

Таким образом, ваш сайт будет получать файлы cookie b.com, при условии, что http://b.com устанавливает файлы cookie.

Следующим шагом будет управление сайтом внутри iframe через JavaScript. Операции внутри iframe могут стать проблемой, если вы не владеете вторым доменом. Но в случае наличия доступа к обоим доменам, ссылаясь на нужную веб-страницу в src iframe, следует предоставить файлы cookie, которые вы хотели бы получить.

Вадим Тюмиров
источник
5
Просто предупреждение: есть некоторые серьезные проблемы с файлами cookie в iframes в Safari. Они, очевидно, не работают кросс-домен.
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

Включить происхождение пользовательского интерфейса и установить для параметра Разрешить 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>
user7712621
источник
1

Я создал модуль NPM, который позволяет вам обмениваться локально сохраненными данными между доменами: https://www.npmjs.com/package/cookie-toss

Используя iframe, размещенный в Домене A, вы можете хранить все свои пользовательские данные в Домене A и ссылаться на эти данные, отправляя запросы в iframe Домена A.

Таким образом, Домены B, C и т. Д. Могут внедрять iframe и отправлять запросы на сохранение и доступ к нужным данным. Домен A становится центром всех общих данных.

С помощью белого списка доменов в Домене A вы можете гарантировать, что только ваши зависимые сайты могут получить доступ к данным в Домене A.

Хитрость заключается в том, чтобы иметь внутри кода iframe в домене A код, который может распознать, какие данные запрашиваются. README в вышеупомянутом модуле NPM углубляется в процедуру.

Надеюсь это поможет!

jmealy
источник
-4

Читать Cookie вWeb 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;
                            }
                        }
                    }
user7712621
источник
Это не решает вопрос использования OP на двух разных доменах
Никлас Вульф