คุกกี้ข้ามโดเมน


247

ฉันมี webapps สอง WebApp1 และ WebApp2 ในสองโดเมนที่ต่างกัน

  1. ฉันกำลังตั้งค่าคุกกี้ใน WebApp1 ใน HttpResponse
  2. วิธีการอ่านคุกกี้เดียวกันจาก HttpRequest ใน WebApp2

ฉันรู้ว่ามันฟังดูแปลกเพราะคุกกี้มีความเฉพาะเจาะจงสำหรับโดเมนที่กำหนดและเราไม่สามารถเข้าถึงได้จากโดเมนที่ต่างกัน อย่างไรก็ตามฉันเคยได้ยินเกี่ยวกับคุกกี้ CROSS-DOMAIN ซึ่งสามารถแชร์กับหลาย ๆ webapps ได้ วิธีการใช้ข้อกำหนดนี้โดยใช้คุกกี้ CROSS-DOMAIN

หมายเหตุ: ฉันกำลังลองกับ J2EE webapps

คำตอบ:


130

ใช่เป็นไปได้อย่างแน่นอนที่จะได้รับคุกกี้จาก 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'] แทน *
Joel Teply

1
นี่คือสิ่งเดียวที่ทำงานให้ฉัน นอกจากนี้ * ไม่ได้รับการยอมรับว่าเป็นจุดกำเนิดดังนั้นจำเป็นต้องใช้ทิปของ @Joel Teply
เดา

4
สิ่งนี้จะไม่ทำงานหากคุกกี้ของบุคคลที่สามถูกปิดใช้งาน (อัตโนมัติสำหรับบางสถานการณ์ของเบราว์เซอร์) ดูblog.zok.pw/web/2015/10/21/3rd-party-cookies-in-practiceและallannienhuis.com/archives/2013/11/03/ …สำหรับข้อมูลเพิ่มเติม
robocat

4
อย่าใช้เคล็ดลับของ Joel เนื่องจากเป็น "สำคัญ" เหมือนกับการตั้งค่าเป็น "*" ซึ่งสามารถเปิดรูโหว่ด้านความปลอดภัยที่ลึกซึ้งเพื่อไม่ให้มีปัญหาดูstackoverflow.com/questions/12001269/…
rogerdpack

5
บนฝั่งเซิร์ฟเวอร์ของโดเมนใด
Nick Manning

127

อย่างที่คนอื่นพูดว่าคุณไม่สามารถแบ่งปันคุกกี้ได้ แต่คุณสามารถทำสิ่งนี้:

  1. รวบรวมคุกกี้ทั้งหมดไว้ในโดเมนเดียวสมมติว่า cookiemaker.com
  2. เมื่อผู้ใช้ส่งคำขอไปที่ example.com คุณจะเปลี่ยนเส้นทางไปที่ cookiemaker.com
  3. cookiemaker.com เปลี่ยนเส้นทางให้เขากลับไปที่ example.com พร้อมข้อมูลที่คุณต้องการ

แน่นอนว่ามันไม่ได้ปลอดภัยอย่างสมบูรณ์และคุณต้องสร้างโปรโตคอลภายในระหว่างแอพของคุณ

ท้ายที่สุดมันจะสร้างความรำคาญให้กับผู้ใช้ถ้าคุณทำสิ่งนั้นในทุก ๆ การร้องขอ แต่ไม่ใช่ถ้าเป็นสิ่งแรก

แต่ฉันคิดว่าไม่มีวิธีอื่น ...


44
หากไม่มีวิธีอื่นแล้ว StackExchange / OpenID ทำงานอย่างไร
Hawken

60
@Hawken StackExchange / OpenID ทำตามกระบวนการเดียวกันตามที่อธิบายไว้ข้างต้น คุณจะถูกนำไปยังไซต์อื่น (SO> SX) ยืนยันตัวตนของคุณแล้วนำกลับไปที่ SO ด้วยข้อมูลที่คุณต้องการ OpenID Specอธิบายเพิ่มเติมถึงแม้ว่าวิกิพีเดียไม่ได้มากขึ้นชัดถ้อยชัดคำ
Nick Q.

1
ผู้ใช้ทั้งหมดเข้าสู่ระบบใน cookiemaker.com จริง ๆ และจะเปลี่ยนเส้นทางผู้ใช้ไปยังเว็บไซต์ต่างๆด้วยข้อความพิเศษและปลอดภัยที่ยืนยันว่าพวกเขาเข้าสู่ระบบและพวกเขาเป็นใคร วิธีการนำไปใช้นั้นขึ้นอยู่กับคุณมีวิธีการที่ไม่สิ้นสุด บางทีคุณสามารถใช้สิ่งนี้: jwt.io
alcuadrado

8
@ Andrew_1510 cookiebakerจะดีกว่า ;-)
Richard Turner

1
นี่คือโพสต์ที่มีแท็กรูปภาพนั่นเป็นทางออกที่ดีกว่าไหม
shaijut

70

เท่าที่ฉันรู้คุกกี้ถูก จำกัด โดยนโยบาย "แหล่งกำเนิดเดียวกัน" อย่างไรก็ตามด้วย CORS คุณสามารถรับและใช้คุกกี้ "เซิร์ฟเวอร์ B" เพื่อสร้างเซสชันถาวรจาก "เซิร์ฟเวอร์ A" บน "เซิร์ฟเวอร์ B"

แม้ว่าจะต้องมีส่วนหัวใน "เซิร์ฟเวอร์ B":

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

และคุณจะต้องส่งธง " withCredentials " ในทุก "เซิร์ฟเวอร์" คำขอ (เช่น: xhr.withCredentials = true;)

คุณสามารถอ่านได้ที่นี่:

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

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


11
งานนี้เคยชินสำหรับผู้ใช้บางเพราะคุกกี้ ธ จะไม่ทำงานหากคุกกี้บุคคลที่สามถูกปิดใช้งานเช่นSafari โดยค่าเริ่มต้นเช่นการตั้งค่าของ Mozilla Google ตัวอย่างเพิ่มเติมและบทความเกี่ยวกับสาเหตุที่ Facebookไม่ใช้คุกกี้ของบุคคลที่สาม
robocat

1
กองแลกเปลี่ยน / openID ใช้ CORS หรือไม่
RayLoveless

1
FWIW ฉันเพียงแค่ทดสอบล ธ ปกติ withCredentials XHR และมันทำงานใน FF / Safari / Chrome ... แม้ว่าฉันจะไม่ต้องสงสัยเลยว่า Facebook / google ใช้รูปแบบที่ซับซ้อนมากขึ้น
rogerdpack

30

ไม่มีสิ่งใดเช่นคุกกี้ข้ามโดเมน คุณสามารถแบ่งปันคุกกี้ระหว่างfoo.example.comและbar.example.comแต่ไม่ระหว่างexample.comและexample2.comและนั่นคือเหตุผลด้านความปลอดภัย


1
สวัสดีขอบคุณสำหรับการตอบกลับคุณสามารถเพิ่มความชัดเจนในส่วนการกำหนดค่าวิธีการสร้าง / กำหนดค่าโดเมนและโดเมนย่อยในสภาพแวดล้อม j2ee ได้หรือไม่?
SundarJavaDeveloper

1
นี่เป็นคำถามที่ปรับให้เข้ากับserverfault.comซึ่งคุณจะได้รับคำตอบจากผู้เชี่ยวชาญในโดเมน
ดารินทินดิมิทรอฟ

สวัสดีฉันพยายามมี webapps สอง WebApp.domain.com ==> ที่นี่ฉันเพิ่มคุกกี้ในลักษณะดังนี้: คุกกี้คุกกี้ = คุกกี้ใหม่ ("namedCookie", "ทดสอบ"); cookie.setDomain ( "domain.com."); response.addCookie (คุกกี้); WebApp1.domain.com ==> ที่นี่ฉันพยายามเข้าถึงคุกกี้ดังต่อไปนี้ แต่ไม่สามารถเข้าถึงคุกกี้ [] cks = request.getCookies (); สำหรับ (int i = 0; i <cks.length; i ++) {out.print ("พบคุกกี้" + cks [i] .getValue ()); } ความคิดใด ๆ เกี่ยวกับเรื่องนี้?
SundarJavaDeveloper

2
บ่อยครั้งที่ทำซ้ำ แต่ไม่จริงดูคำตอบของฉันด้านล่างหรือที่นี่stackoverflow.com/questions/16186645/…
Raphael Jeger

4
แชร์คุกกี้ระหว่างfoo.example.comและbar.example.comอย่างไร
เจฟฟ์เทียน

24

ทางออกที่ฉลาดที่สุดคือทำตามเส้นทางของ Facebook ในเรื่องนี้ Facebook จะรู้ได้อย่างไรว่าคุณเป็นใครเมื่อคุณเยี่ยมชมโดเมนใด ๆ จริงๆแล้วมันง่ายมาก:

ปุ่มไลค์อนุญาตให้ Facebook ติดตามผู้เยี่ยมชมไซต์ภายนอกทั้งหมดไม่ว่าพวกเขาจะคลิกหรือไม่ก็ตาม Facebook สามารถทำได้เนื่องจากใช้iframeเพื่อแสดงปุ่ม iframe เป็นสิ่งที่คล้ายกับหน้าต่างเบราว์เซอร์ที่ฝังอยู่ภายในหน้า ความแตกต่างระหว่างการใช้ iframe และภาพที่ง่ายสำหรับปุ่มคือการที่iframe มีหน้าเว็บที่สมบูรณ์แบบ - จาก Facebook ไม่มีอะไรเกิดขึ้นในหน้านี้ยกเว้นปุ่มและข้อมูลเกี่ยวกับจำนวนคนที่ชอบหน้าปัจจุบัน

ดังนั้นเมื่อคุณเห็นปุ่มถูกใจบน cnn.com คุณกำลังเยี่ยมชมหน้า Facebook ในเวลาเดียวกัน ที่อนุญาตให้ Facebook อ่านคุกกี้ในคอมพิวเตอร์ของคุณซึ่งสร้างขึ้นครั้งล่าสุดที่คุณเข้าสู่ Facebook

กฎความปลอดภัยขั้นพื้นฐานในทุกเบราว์เซอร์คือเฉพาะเว็บไซต์ที่สร้างคุกกี้เท่านั้นที่สามารถอ่านได้ในภายหลัง และนั่นคือข้อดีของ iframe: ช่วยให้ Facebook สามารถอ่านคุกกี้ Facebook ของคุณแม้ว่าคุณจะเยี่ยมชมเว็บไซต์อื่น นั่นเป็นวิธีที่พวกเขาจำคุณได้ใน cnn.com และแสดงเพื่อนของคุณที่นั่น

ที่มา:


6
ฉันคิดว่า iframe จะไม่ค่อยจัดว่าดีที่สุดหรือเป็นวิธีที่ฉลาดที่สุดในการทำอะไร .. แต่มันเป็นวิธีที่ง่ายที่สุด
Orun

13

ทำในสิ่งที่ Google ทำ สร้างไฟล์ PHP ที่ตั้งค่าคุกกี้ในทั้ง 3 โดเมน จากนั้นในโดเมนที่จะตั้งค่าชุดรูปแบบให้สร้างไฟล์ HTML ที่จะโหลดไฟล์ PHP ที่ตั้งค่าคุกกี้ในอีก 2 โดเมน ตัวอย่าง:

<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 เอกสารจะโหลดเฉพาะเมื่อรูปภาพโหลดอย่างสมบูรณ์นั่นคือเมื่อตั้งค่าคุกกี้ไว้ในอีก 2 โดเมน Onload Callback:

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

setcookie.php

เราตั้งค่าคุกกี้ในโดเมนอื่น ๆ โดยใช้ไฟล์ PHP ดังนี้:

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

ขณะนี้มีการตั้งค่าคุกกี้ในสามโดเมน


2
สิ่งนี้จะไม่ทำงานหากเปิดใช้งานคุณลักษณะ 'บล็อกคุกกี้ของบุคคลที่สาม'
Jens

11

คุณไม่สามารถแบ่งปันคุกกี้ข้ามโดเมน อย่างไรก็ตามคุณสามารถอนุญาตให้โดเมนย่อยทั้งหมดสามารถเข้าถึงได้ ในการอนุญาตให้โดเมนย่อยทั้งหมดที่จะมีการเข้าถึงการตั้งค่าโดเมนexample.com.example.com

เป็นไปไม่ได้ที่จะให้otherexample.comเข้าถึงexample.comคุกกี้ของ


27
ทำไม.google.comคุกกี้ปรากฏขึ้นเมื่อเรียกดู YouTube แล้ว?
Hawken

20
แท็กการวิเคราะห์ของ Google คุกกี้เหล่านั้นมาจาก google.com ไม่ใช่จาก youtube.com
ธันวาคม

8

คุณสามารถพยายามดัน val คุกกี้ไปยังโดเมนอื่นโดยใช้แท็กรูปภาพ

ระยะของคุณอาจแตกต่างกันไปเมื่อพยายามทำเช่นนี้เนื่องจากเบราว์เซอร์บางตัวกำหนดให้คุณต้องมีนโยบาย P3Pที่เหมาะสมในโดเมน WebApp2 มิฉะนั้นเบราว์เซอร์จะปฏิเสธคุกกี้

หากคุณดูนโยบาย plus.google.com p3p คุณจะเห็นว่านโยบายของพวกเขาคือ:

CP = "นี่ไม่ใช่นโยบาย P3P! ดูhttp://www.google.com/support/accounts/bin/answer.py?hl=th&answer=151657สำหรับข้อมูลเพิ่มเติม"

นั่นคือนโยบายที่พวกเขาใช้สำหรับปุ่ม +1 ของพวกเขาสำหรับการร้องขอข้ามโดเมนเหล่านี้

คำเตือนอีกอย่างหนึ่งคือหากคุณใช้ https ให้แน่ใจว่าแท็กภาพชี้ไปยังที่อยู่ https ด้วยมิฉะนั้นคุกกี้จะไม่ถูกตั้งค่า


2
สนใจที่จะอธิบายรายละเอียดเล็กน้อย?
บ่อย

5

มีภาพรวมที่ดีว่า Facebook ดำเนินการที่นี่บน nfriedly.com อย่างไร

นอกจากนี้ยังมี Browser Fingerprinting ซึ่งไม่เหมือนกับคุกกี้ แต่มีจุดประสงค์คล้ายกันในการช่วยให้คุณระบุผู้ใช้ในระดับที่แน่นอน มีโพสต์ที่นี่ใน Stack Overflowที่อ้างอิงตามวิธีการหนึ่งในการพิมพ์ลายนิ้วมือ


1

หนึ่งสามารถใช้ iframe ที่มองไม่เห็นเพื่อรับคุกกี้ สมมติว่ามีสองโดเมนคือ a.com และ b.com สำหรับ index.html ของโดเมน a.com สามารถเพิ่มได้ (สังเกตความสูง = 0 ความกว้าง = 0):

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

ด้วยวิธีนี้เว็บไซต์ของคุณจะได้รับคุกกี้ b.com โดยสมมติว่าhttp://b.comตั้งค่าคุกกี้

สิ่งต่อไปคือการจัดการเว็บไซต์ภายใน iframe ผ่าน JavaScript การดำเนินการภายใน iframe อาจกลายเป็นความท้าทายหากไม่มีโดเมนที่สอง แต่ในกรณีที่มีการเข้าถึงทั้งสองโดเมนที่อ้างถึงหน้าเว็บที่ถูกต้องที่ src ของ iframe ควรให้คุกกี้หนึ่งที่ต้องการที่จะได้รับ


5
เพียงคำเตือน: มีปัญหาร้ายแรงเกี่ยวกับคุกกี้ใน 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

รวมที่มาของ 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>

1

ฉันได้สร้างโมดูล NPM ซึ่งช่วยให้คุณสามารถแบ่งปันข้อมูลที่เก็บไว้ในเครื่องข้ามโดเมน: https://www.npmjs.com/package/cookie-toss

ด้วยการใช้ iframe ที่โฮสต์บนโดเมน A คุณสามารถจัดเก็บข้อมูลผู้ใช้ทั้งหมดของคุณบนโดเมน A และอ้างอิงข้อมูลนั้นโดยโพสต์คำขอไปยังโดเมน A iframe

ดังนั้นโดเมน B, C, ฯลฯ สามารถฉีด iframe และโพสต์คำขอไปยังร้านค้าและเข้าถึงข้อมูลที่ต้องการ โดเมน A กลายเป็นฮับสำหรับข้อมูลที่แชร์ทั้งหมด

ด้วยรายการที่อนุญาตของโดเมนภายใน Domain A คุณสามารถมั่นใจได้ว่าเฉพาะไซต์ที่ต้องพึ่งพาของคุณเท่านั้นที่สามารถเข้าถึงข้อมูลบนโดเมน A ได้

เคล็ดลับคือการมีรหัสอยู่ใน iframe บนโดเมน A ซึ่งสามารถรับรู้ว่าต้องการข้อมูลใด README ในโมดูล NPM ด้านบนมีความลึกมากขึ้นในขั้นตอน

หวังว่านี่จะช่วยได้!


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

สิ่งนี้ไม่ได้ตอบคำถาม OP เกี่ยวกับการใช้ในสองโดเมนที่ต่างกัน
Niklas Wulff
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.