Çapraz kaynak istekleri için çerezleri ayarlayın


97

Çerezler çapraz kaynak nasıl paylaşılır? Daha spesifik olarak, Set-Cookiebaşlık ile birlikte başlık nasıl kullanılır Access-Control-Allow-Origin?

İşte durumumun açıklaması:

localhost:4000Barındırılan bir web uygulamasında çalışan bir API için çerez ayarlamaya çalışıyorum localhost:3000.

Görünüşe göre tarayıcıda doğru yanıt başlıklarını alıyorum, ancak maalesef hiçbir etkisi yok. Yanıt başlıkları şunlardır:

HTTP / 1.1 200 Tamam
Erişim Kontrolü-İzin Ver-Kaynak: http: // localhost: 3000
Vary: Origin, Accept-Encoding
Set-Cookie: token = 0d522ba17e130d6d19eb9c25b7ac58387b798639f81ffe75bd449afbc3cc715d6b038e426adeac3316f0511dc7fae3f7; Maksimum Yaş = 86400; Etki alanı = localhost: 4000; Yol = /; Bitiş Tarihi = Sal, 19 Eylül 2017 21:11:36 GMT; HttpOnly
İçerik Türü: uygulama / json; karakter kümesi = utf-8
İçerik Uzunluğu: 180
ETag: W / "b4-VNrmF4xNeHGeLrGehNZTQNwAaUQ"
Tarih: Pzt, 18 Eylül 2017 21:11:36 GMT
Bağlantı: canlı tutma

Ayrıca, Response CookiesChrome'un geliştirici araçlarının Ağ sekmesini kullanarak trafiği incelediğimde altındaki çerezi görebiliyorum . Yine de, altındaki Uygulama sekmesinde ayarlanan bir çerez göremiyorum Storage/Cookies. Herhangi bir CORS hatası görmüyorum, bu yüzden başka bir şeyi kaçırdığımı varsayıyorum.

Herhangi bir öneri?

Güncelleme I:

Sunucudaki bir uç noktaya istek göndermek için bir React-Redux uygulamasındaki istek modülünü kullanıyorum /signin. Sunucu için express kullanıyorum.

Ekspres sunucu:

res.cookie ('jeton', 'xxx-xxx-xxx', {maxAge: 86400000, httpOnly: true, domain: 'localhost: 3000'})

Tarayıcıda istek:

request.post ({uri: '/ signin', json: {userOne: 'userOne', şifre: '123456'}}, (err, response, body) => {
    // bir şeyler yapmak
})

Güncelleme II:

İstek ve yanıt başlıklarını şimdi çılgın gibi ayarlıyorum, hem istek hem de yanıtta mevcut olduklarından emin oluyorum. Aşağıda bir ekran görüntüsü var. Başlıkları dikkat Access-Control-Allow-Credentials, Access-Control-Allow-Headers, Access-Control-Allow-Methodsve Access-Control-Allow-Origin. Axios'un github'ında bulduğum soruna baktığımda, gerekli tüm başlıkların artık ayarlandığı izlenimi altındayım. Yine de şans yok ...

görüntü açıklamasını buraya girin


4
@PimHeijden şuna bir göz atın: developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/… belki de withCredentials'ın kullanımı ihtiyacınız olan şeydir?
Kalamarico

2
Tamam, istek kullanıyorsunuz ve bunun en iyi seçenek olmadığını düşünüyorum, bu yazıya bir göz atın ve cevaba, aksiyolar bence sizin için yararlı olabilir. stackoverflow.com/questions/39794895/…
Kalamarico

Teşekkürler! requestModülün tarayıcıda kullanılmak üzere tasarlanmadığını fark edemedim. Axios şu ana kadar harika bir iş çıkarmış gibi görünüyor. Şimdi hem başlık alırsınız: Access-Control-Allow-Credentials:trueve Access-Control-Allow-Origin:http://localhost:3000(CORS'yi etkinleştirmek için kullanılır). Bu doğru görünüyor ama Set-Cookiebaşlık hiçbir şey yapmıyor ...
Pim Heijden

Aynı sorun, ancak doğrudan Axios kullanılıyor: stackoverflow.com/q/43002444/488666 . { withCredentials: true }Axios tarafında gerçekten gerekli olsa da, sunucu başlıklarının da dikkatlice kontrol edilmesi gerekir (bkz. Stackoverflow.com/a/48231372/488666 )
Frosty Z

hangi sunucu başlıkları?
Pim Heijden

Yanıtlar:


155

Ne yapmak gerekiyor

Bir CORS isteği ile tanımlama bilgilerinin başarıyla alınmasına ve gönderilmesine izin vermek için aşağıdakileri yapın.

Arka uç (sunucu): HTTP başlık Access-Control-Allow-Credentialsdeğerini olarak ayarlayın true. Ayrıca, emin olun HTTP başlıkları Access-Control-Allow-Originve Access-Control-Allow-Headersve ayarlanır değil joker ile* .

Express js'de CORS ayarlama hakkında daha fazla bilgi için buradaki belgeleri okuyun

Ön uç (istemci):XMLHttpRequest.withCredentials Bayrağı olarak ayarlayın true, bu, kullanılan istek-yanıt kitaplığına bağlı olarak farklı şekillerde gerçekleştirilebilir:

Veya

CORS'u çerezlerle birlikte kullanmak zorunda kalmayın. Bunu bir vekil ile başarabilirsiniz.

Her ne sebeple olursa olsun, bundan kaçınmayın. Çözüm yukarıda.

Alan bir bağlantı noktası içeriyorsa Chrome'un çerezi ayarlamayacağı ortaya çıktı. Bunu localhost(bağlantı noktası olmadan) için ayarlamak bir sorun değildir. Bu ipucu için Erwin'e çok teşekkürler !


2
Sanırım bu sorunu localhostşuradaki kontrol etmenizden dolayı yaşıyorsunuz : stackoverflow.com/a/1188145 ve bu da sizin durumunuza yardımcı olabilir ( stackoverflow.com/questions/50966861/… )
Edwin

5
Bu cevap bana çok yardımcı oldu! Bulmak uzun zaman aldı. Ancak cevabın Access-Control-Allow-Origin, sadece açık bir alana ayarlamanın "*"gerekli olmadığını da belirtmesi gerektiğini düşünüyorum . O zaman mükemmel bir cevap olurdu
e.dan

6
bu iyi bir cevaptır ve CORS, üstbilgiler, arka uç ve ön uç için tüm kurulumlar ve gerçek alt etki alanıyla yerel olarak / etc / hosts geçersiz kılma ile localhost'tan kaçınmak, yine de postacıların yanıt başlıklarında SET-COOKIE gösterdiğini ancak krom hata ayıklamasının olmadığını görüyorum bunu yanıt başlıklarında gösterin ve ayrıca çerez aslında Chrome'da ayarlanmaz. Kontrol edilecek başka fikir var mı?
bjm88

1
@ bjm88 Bunu anlamaya mı başladınız? Ben de aynı durumdayım. Çerez, localhost: 3010'dan localhost: 5001'e bağlanırken doğru şekilde ayarlandı, ancak localhost: 3010'dan fakeremote: 5001'e (ana bilgisayar dosyamda 127.0.0.1'e işaret ediyor) çalışmıyor. Sunucumu özel bir etki alanına sahip gerçek bir sunucuda barındırdığımda da aynı şey oluyor (localhost: 3010'dan mydomain.com'a bağlanma). Bu cevapta önerilenlerin hepsini yaptım ve birçok başka şeyi denedim.
Form

1
Angular'da, gerekli istemci tarafı değişikliği de withCredentials eklenmesidir: HttpClient.post, .get, options, vb .'ye iletilen seçenekler için doğrudur
Marvin

13

2020'de yayınlanan Chrome Tarayıcı için not.

Chrome'un gelecekteki bir sürümü, yalnızca SameSite=Noneve ile ayarlanmışlarsa siteler arası istekler içeren çerezleri sunacaktır Secure.

Dolayısıyla, arka uç sunucunuz SameSite = None olarak ayarlamazsa, Chrome varsayılan olarak SameSite = Lax kullanır ve bu çerezi {withCredentials: true} istekleriyle kullanmaz.

Daha fazla bilgi https://www.chromium.org/updates/same-site .

Firefox ve Edge geliştiricileri de gelecekte bu özelliği yayınlamak istiyor.

Burada bulunan özellikler: https://tools.ietf.org/html/draft-west-cookie-incrementalism-01#page-8


2
aynı site = yok ve güvenli bayrak sağlanması HTTPS gerektirir. HTTPS'nin bir seçenek olmadığı yerel bir sistemde bunu nasıl başarabilirim? bir şekilde baypas edebilir miyiz?
nirmal patel

@nirmalpatel Chome dev konsolundaki "Lax" değerini kaldırmanız yeterlidir.
LennyLip

3

Müşterinin çapraz kaynaklı isteklerden gelen çerezleri okuyabilmesi için şunlara sahip olmanız gerekir:

  1. Sunucudan gelen tüm yanıtların başlıklarında aşağıdakilerin olması gerekir:

    Access-Control-Allow-Credentials: true

  2. Müşterinin tüm istekleri withCredentials: trueseçenekle göndermesi gerekir

Angular 7 ve Spring Boot ile yaptığım uygulamada bunu şu şekilde başardım:


Sunucu tarafı:

@CrossOrigin(origins = "http://my-cross-origin-url.com", allowCredentials = "true")
@Controller
@RequestMapping(path = "/something")
public class SomethingController {
  ...
}

origins = "http://my-cross-origin-url.com"Bölüm katacak Access-Control-Allow-Origin: http://my-cross-origin-url.comher sunucu yanıtının başlığına

allowCredentials = "true"Bölüm katacak Access-Control-Allow-Credentials: trueçerezleri okumak müşteri için sipariş ihtiyacımız olan şey her sunucunun cevap başlığında, için


İstemci tarafı:

import { HttpInterceptor, HttpXsrfTokenExtractor, HttpRequest, HttpHandler, HttpEvent } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from 'rxjs';

@Injectable()
export class CustomHttpInterceptor implements HttpInterceptor {

    constructor(private tokenExtractor: HttpXsrfTokenExtractor) {
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // send request with credential options in order to be able to read cross-origin cookies
        req = req.clone({ withCredentials: true });

        // return XSRF-TOKEN in each request's header (anti-CSRF security)
        const headerName = 'X-XSRF-TOKEN';
        let token = this.tokenExtractor.getToken() as string;
        if (token !== null && !req.headers.has(headerName)) {
            req = req.clone({ headers: req.headers.set(headerName, token) });
        }
        return next.handle(req);
    }
}

Bu sınıfla aslında tüm isteğinize ek şeyler enjekte edersiniz.

İlk bölüm req = req.clone({ withCredentials: true });, her bir talebi withCredentials: trueseçenekle göndermek için ihtiyacınız olan şeydir . Bu, pratikte bir OPTION isteğinin gönderileceği anlamına gelir, böylece çerezlerinizi ve aralarında yetkilendirme jetonunu, bu jetonun (başlıkta) eklenmesine ihtiyaç duyan gerçek POST / PUT / DELETE isteklerini göndermeden önce, sunucunun isteği doğrulaması ve yürütmesi için sipariş.

İkinci bölüm, tüm istekler için bir anti-CSRF belirtecini özel olarak işleyen bölümdür. Gerektiğinde çerezden okur ve her isteğin başlığına yazar.

İstenilen sonuç şuna benzer:

tepki istek


Bu cevap mevcut olana ne katıyor?
Pim Heijden

1
Gerçek bir uygulama. Yayınlamaya karar vermemin nedeni, aynı konuyu araştırmak ve bunu gerçekleştirmek için çeşitli yazılardan parçalar eklemek için çok zaman harcamaktır. Birinin aynı şeyi yapması, bu gönderiyi bir karşılaştırma olarak alması çok daha kolay olmalı.
Stefanos Kargas

Ek açıklamada ayarın allowCredentials = "true"gösterilmesi @CrossOriginbana yardımcı oldu.
37'de ponder275

@lennylip yukarıdaki cevabında bahsedilen, aynı site ve güvenli bayrak için hata gösteriyor. Güvenli bayrak olmadan localhost sunucusuyla bunu nasıl başarabilirsiniz
nirmal patel

0

Pim'in cevabı çok yardımcı oluyor. Benim durumumda kullanmak zorundayım

Expires / Max-Age: "Session"

Bir dateTime ise, süresi dolmamış olsa bile, çerezi arka uca yine de göndermez:

Expires / Max-Age: "Thu, 21 May 2020 09:00:34 GMT"

Umarım aynı sorunla karşılaşabilecek gelecekteki insanlar için yararlıdır.


0

Ekspres için ekspres kitaplığınızı şu sürüme yükseltin: 4.17.1 , en son kararlı sürüm olan . Sonra;

CorsOption In: Set originsizin localhost url veya ön uç üretim url ve credentialshiç true örn

  const corsOptions = {
    origin: config.get("origin"),
    credentials: true,
  };

Kaynağımı yapılandırma npm modülünü kullanarak dinamik olarak ayarlıyorum .

Ardından res.cookie'de:

Localhost için: aynı Site ve güvenli seçeneğini belirlemenize gerek yoktur, XSS saldırısını ve diğer kullanışlı seçenekleri önlemek için http çerezi olarak ayarlayabilirsiniz httpOnly.true sizin kullanım durumuna bağlı olarak.

Üretim ortamı sameSiteiçin none, çapraz kaynak talebi için ve secureolarak ayarlamanız gerekir true. Unutmayın sameSite, şu anda yalnızca ekspres son sürümle çalışır ve en son Chrome sürümü yalnızca çerezi ayarlarhttps , bu nedenle güvenli seçenek gerekir.

İşte benimkini nasıl dinamik hale getirdim

 res
    .cookie("access_token", token, {
      httpOnly: true,
      sameSite: app.get("env") === "development" ? true : "none",
      secure: app.get("env") === "development" ? false : true,
    })
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.