Dlaczego metoda .ajax () jquery nie wysyła mojego pliku cookie sesji?


338

Po zalogowaniu się za pośrednictwem $.ajax()witryny próbuję wysłać drugie $.ajax()żądanie do tej witryny - ale gdy sprawdzę nagłówki wysłane za pomocą FireBug, w żądaniu nie zostanie uwzględniony plik cookie sesji.

Co ja robię źle?


2
Plik cookie ajax może pojawić się po pliku cookie, a FireBug może przechwycić plik cookie na pierwszej stronie.
Chris

1
Nie rozumiem, co masz na myśli, ale mogę powiedzieć, że jeśli wkleję adres URL żądania w pasku adresu przeglądarki i ponownie sprawdzę Firebug, widzę ciasteczko w nagłówkach wysyłanych do serwera. Jakieś rozwiązania?
user345625

Myślę więc, że ajax będzie również obsługiwał to samo, co przeglądarka
user345625

Jakiego kodu używasz?
Dean Harding

przeglądarka nadal tworzy pliki cookie ustawione przez serwer podczas żądania ajax, jquery lub w inny sposób. Czy sprawdziłeś odpowiedź na żądanie ajax i upewniłeś się, że pliki cookie wróciły z serwera, który chcesz ustawić? Może występować problem z kodem serwera, który nawet nie ustawia ciasteczka itp.
David

Odpowiedzi:


218

Połączenia AJAX wysyłają pliki cookie tylko wtedy, gdy adres, do którego dzwonisz, znajduje się w tej samej domenie, co skrypt wywołujący.

Może to być problem między domenami.

Być może próbowałeś zadzwonić na adres URL z www.domain-a.comwłączonego skryptu wywołującego www.domain-b.com(innymi słowy: nawiązałeś połączenie między domenami, w którym to przypadku przeglądarka nie wyśle ​​żadnych plików cookie w celu ochrony Twojej prywatności).

W takim przypadku masz następujące opcje:

  • Napisz mały serwer proxy, który znajduje się w domenie-b, i przekaże twoje żądania do domeny-a. Twoja przeglądarka pozwoli ci zadzwonić do proxy, ponieważ jest on na tym samym serwerze, co skrypt wywołujący.
    Ten serwer proxy może następnie zostać skonfigurowany tak, aby akceptował nazwę pliku cookie i parametr wartości, które może wysłać do domeny-a. Ale aby to zadziałało, musisz znać nazwę pliku cookie i docenić swój serwer w domenie - a chce uwierzytelnienia.
  • Jeśli pobierasz obiekty JSON, spróbuj zamiast tego użyć żądania JSONP . jQuery obsługuje je. Ale musisz zmienić usługę w domenie-a, aby zwracała prawidłowe odpowiedzi JSONP.

Cieszę się, że to pomogło choć trochę.


19
Warto również zauważyć, że pliki cookie można ustawić na określoną ścieżkę, więc jeśli plik cookie został ustawiony za pomocą path=/somethingi poprosisz o stronę, /anotherplik cookie nie zostanie wysłany. Gdy poprosisz o stronę, /somethingplik cookie zostanie wysłany zgodnie z oczekiwaniami. Więc sprawdź kod, który ustawia ciasteczko.
styfle

2
czy żądanie jsonp wysyła coockies?
albanx

1
@albanx Tak, jeśli są wymienione wymagania, które wymieniłem. To zwykłe żądanie, jak każde inne, i jako takie wysyła pliki cookie.
grypa

1
@albanx to inne powiązane pytanie zawiera przykład, jak zrobić to żądanie JSONP za pomocą niestandardowych plików cookie
AntonioHerraizS

4
Według JSONP na Wikipedii> to podejście zostało porzucone na rzecz CORS
Peter Dotchev

388

Działam w scenariuszu między domenami. Podczas logowania serwer zdalny zwraca nagłówek Set-Cookie wraz z Access-Control-Allow-Credentialsustawieniem na true.

Następne wywołanie ajax do zdalnego serwera powinno użyć tego pliku cookie.

CORS Access-Control-Allow-Credentialsumożliwia rejestrowanie w wielu domenach. Sprawdź https://developer.mozilla.org/En/HTTP_access_control dla przykładów.

Dla mnie wygląda to na błąd w JQuery (lub przynajmniej w przyszłej wersji).

AKTUALIZACJA:

  1. Pliki cookie nie są ustawiane automatycznie na podstawie odpowiedzi AJAX (cytowanie: http://aleembawany.com/2006/11/14/anatomy-of-a-well-designed-ajax-login-experience/ )

    Dlaczego?

  2. Nie można uzyskać wartości pliku cookie z odpowiedzi, aby ustawić go ręcznie ( http://www.w3.org/TR/XMLHttpRequest/#dom-xmlhttprequest-getresponseheader )

    Jestem zmieszany..

    Powinien istnieć sposób jquery.ajax()na ustawienie XMLHttpRequest.withCredentials = "true"parametru.

ODPOWIEDŹ: Powinieneś użyć xhrFieldsparam z http://api.jquery.com/jQuery.ajax/

Przykład w dokumentacji to:

$.ajax({
   url: a_cross_domain_url,
   xhrFields: {
      withCredentials: true
   }
});

Ważne jest również, aby serwer poprawnie odpowiedział na to żądanie. Skopiuj tutaj świetne komentarze z @ Frédéric i @Pebbl:

Important note: when responding to a credentialed request, server must specify a domain, and cannot use wild carding. The above example would fail if the header was wildcarded as: Access-Control-Allow-Origin: *

Więc kiedy prośba jest:

Origin: http://foo.example
Cookie: pageAccess=2

Serwer powinien odpowiedzieć:

Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Credentials: true

[payload]

W przeciwnym razie ładunek nie zostanie zwrócony do skryptu. Zobacz: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials


8
Wspaniały ! Dodaję, aby użyć tego + zestawu nagłówka Access-Control-Allow-Credentials na true po stronie serwera
Frédéric,

i gdzie ustawić te poświadczenia? w Autoryzacji nagłówka? w treści żądania?
Francisco Corrales Morales,

3
Dzięki za odpowiedź :) tylko szybki dodatek, warto wspomnieć Important note: when responding to a credentialed request, server must specify a domain, and cannot use wild carding. The above example would fail if the header was wildcarded as: Access-Control-Allow-Origin: * developer.mozilla.org/en-US/docs/Web/HTTP/…
Pebbl

Niestety, nic z tego nie działało. Jeśli uruchomię to samo żądanie z AngularJS, to działa, ale z jQuery, nawet z tymi sugestiami, plik cookie sesji nie jest przekazywany. (jQuery
v2.1.1

(OO) Uratowałeś mnie od różnych bolesnych godzin. Cóż za idealna odpowiedź! Dzięki! Musiałem dodać je w publicznym katalogu głównym .htaccess mojej witryny: <IfModule mod_headers.c> Zestaw nagłówka Access-Control-Allow-Origin „ localhost ” Zestaw nagłówka Access-Control-Allow-Credentials „true” </IfModule>
Vinay Vissh

48

Za pomocą

xhrFields: { withCredentials:true }

w ramach mojego wywołania jQuery ajax było tylko częścią rozwiązania. Musiałem także zwrócić nagłówki w odpowiedzi OPTIONS z mojego zasobu:

Access-Control-Allow-Origin : http://www.wombling.com
Access-Control-Allow-Credentials : true

Ważne było, aby tylko jeden dozwolony „początek” był w nagłówku odpowiedzi wywołania OPTIONS, a nie „*”. Osiągnąłem to, czytając pochodzenie z żądania i wypełniając je z powrotem w odpowiedzi - prawdopodobnie obchodząc pierwotny powód ograniczenia, ale w moim przypadku bezpieczeństwo nie jest najważniejsze.

Pomyślałem, że warto wyraźnie wspomnieć o wymogu tylko jednego źródła, ponieważ standard W3C pozwala na listę oddzieloną spacjami - ale Chrome nie! http://www.w3.org/TR/cors/#access-control-allow-origin-response-header NB bit „w praktyce”.


41

Umieść to w swojej funkcji init:

$.ajaxSetup({
  xhrFields: {
    withCredentials: true
  }
});

To będzie działać.


1
Uratowałeś mi dzień! Na poziomie metody withCredentials nie działało dla mnie. Ale globalnie taki jak to w końcu działa! Dzięki.
Paulius Matulionis,

bądź ostrożny, ponieważ wyśle ​​pliki cookie do wszystkich żądań, eter dla innych domen (co nie jest tego oczekiwane i nie powiedzie się przez żądanie kontroli dostępu-Zezwalaj-Poświadcz)
gdbdable

12

Istnieje już wiele dobrych odpowiedzi na to pytanie, ale pomyślałem, że pomocne może być wyjaśnienie przypadku, w którym można oczekiwać, że sesyjny plik cookie zostanie wysłany, ponieważ domena cookie jest zgodna, ale nie zostanie wysłany, ponieważ żądanie AJAX jest przeniesiony do innej subdomeny. W tym przypadku mam plik cookie przypisany do domeny * .mydomain.com i chcę, aby został on uwzględniony w żądaniu AJAX do pliku different.mydomain.com ”. Domyślnie plik cookie nie jest wysyłany. Nie musisz wyłączać HTTPONLY w pliku cookie sesji, aby rozwiązać ten problem. Musisz tylko zrobić to, co sugeruje wombling ( https://stackoverflow.com/a/23660618/545223 ) i wykonać następujące czynności.

1) Dodaj następujące elementy do żądania ajax.

xhrFields: { withCredentials:true }

2) Dodaj do nagłówków odpowiedzi następujące zasoby w różnych subdomenach.

Access-Control-Allow-Origin : http://original.mydomain.com
Access-Control-Allow-Credentials : true

7

Po wypróbowaniu innych rozwiązań i wciąż niedziałaniu, dowiedziałem się, jaki jest problem w moim przypadku. Zmieniłem contentType z „application / json” na „text / plain”.

$.ajax(fullUrl, {
    type: "GET",
    contentType: "text/plain",
    xhrFields: {
         withCredentials: true
    },
    crossDomain: true
});

4

Miałem ten sam problem i przeprowadzając kilka kontroli, mój skrypt po prostu nie otrzymywał pliku cookie sessionid.

Zorientowałem się, patrząc na wartość cookie sessionid w przeglądarce, że mój framework (Django) przekazuje cookie sessionid z HttpOnly jako domyślną. Oznaczało to, że skrypty nie miały dostępu do wartości sessionid i dlatego nie przekazywały jej wraz z żądaniami. To śmieszne, że HttpOnly byłby wartością domyślną, gdy tak wiele rzeczy używa Ajax, które wymagałyby ograniczenia dostępu.

Aby to naprawić, zmieniłem ustawienie (SESSION_COOKIE_HTTPONLY = False), ale w innych przypadkach może to być flaga „HttpOnly” na ścieżce pliku cookie


2
Nie rób tego. Umożliwia dostęp skryptu po stronie klienta do pliku cookie sesji, który jest najczęstszym wektorem ataku XSS. owasp.org/index.php/HttpOnly
Jason Elkin


0

Tylko moje 2 centy za ustawienie problemu z ciasteczkami PHPSESSID na localhost i w środowisku deweloperskim. Wykonuję wywołanie AJAX do punktu końcowego interfejsu API REST na locahost. Powiedz, że jego adres to mysite.localhost/api/member/login/(virtal host w moim środowisku programistycznym).

  • Kiedy przesyłam to żądanie do Listonosza , wszystko idzie dobrze, a odpowiedź PHPSESSID jest ustawiona.

  • Kiedy żądam tego punktu końcowego za pośrednictwem AJAX ze strony proxy Browsersync (np. Z 122.133.1.110:3000/test/api/login.phpwiersza adresu mojej przeglądarki sprawdź, czy domena jest inna niż mysite.localhost) PHPSESSID nie pojawia się wśród plików cookie.

  • Kiedy mysite.localhost/test/api/login.phpwysyłam to żądanie bezpośrednio ze strony w tej samej domenie (tj. ) PHPSESSID jest w porządku.

Jest to więc problem dotyczący plików cookie pochodzących z różnych źródeł, jak wspomniano w odpowiedzi @flu powyżej


0

Dodanie mojego scenariusza i rozwiązania na wypadek, gdyby pomógł komuś innemu. Podobny przypadek napotkałem podczas używania interfejsów API RESTful. Mój serwer WWW obsługujący pliki HTML / Script / CSS i interfejsy API serwera aplikacji udostępniające były hostowane w tej samej domenie. Jednak ścieżka była inna.

serwer WWW - mojadomena / webpages /abc.html

używał abc.js, który ustawił plik cookie o nazwie mycookie

serwer aplikacji - moja_domena / webapis / nazwa_usługi.

do których wykonano połączenia API

Spodziewałem się pliku cookie w mojej domenie / webapis / nazwa_usługi i próbowałem go przeczytać, ale nie został wysłany. Po przeczytaniu komentarza z odpowiedzi sprawdziłem w narzędziu programistycznym przeglądarki, że ścieżka mycookie została ustawiona na „/ webpages ”, a zatem nie jest dostępna w zgłoszeniu serwisowym do

mojadomena / webapis / nazwa_usługi

Więc ustawiając ciasteczko z jquery, właśnie to zrobiłem -

$.cookie("mycookie","mayvalue",{**path:'/'**});

-5

Być może nie w 100% odpowiadając na pytanie, ale natknąłem się na ten wątek, mając nadzieję na rozwiązanie problemu z sesją, gdy publikowanie w pliku ładuje plik z menedżera zasobów edytora innovastudio. Ostatecznie rozwiązanie było proste: mają Flash-Uploader. Wyłączanie tego (ustawienie

var flashUpload = false;   

w pliku asset.php), a kontrolki ponownie zaczęły migać.

Ponieważ te problemy mogą być bardzo trudne do debugowania, odkryłem, że umieszczenie czegoś takiego jak poniżej w programie do przesyłania przesyła cię (cóż, w tym przypadku ja) na właściwą ścieżkę:

$sn=session_name();
error_log("session_name: $sn ");

if(isset($_GET[$sn])) error_log("session as GET param");
if(isset($_POST[$sn])) error_log("session as POST param");
if(isset($_COOKIE[$sn])) error_log("session as Cookie");
if(isset($PHPSESSID)) error_log("session as Global");

Zanurkowałem w dzienniku i szybko zauważyłem brakującą sesję, w której nie wysłano ciasteczka.


Nie sądzę, żeby powyższy przykład działał, ponieważ gdyby nie było ciasteczka sesyjnego, jaka byłaby wartość $ sn? (losowy, a może zerowy), alternatywnie użytkownicy mogliby ustawić session_name z wartości GET, na przykład w session_name(isset($_GET['sess']) ? $_GET['sess'] : null);session_start();ten sposób dostaliby działający element
Steel Brain

Właśnie w ten sposób znalazłem problem: brak sesji podczas publikowania z tego flashowego programu ładującego. Ponieważ używanie identyfikatora sesji zmiennej GET to zły pomysł, a plik cookie nie działał, wyrzuciłem go. Kogo to obchodzi, flash i tak należy już do przeszłości.
Ellert van Koperen
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.