Warum sendet die .ajax () -Methode von jquery mein Sitzungscookie nicht?

338

Nachdem $.ajax()ich mich über eine Site $.ajax()angemeldet habe, versuche ich, eine zweite Anfrage an diese Site zu senden. Wenn ich jedoch die mit FireBug gesendeten Header überprüfe, ist in der Anfrage kein Sitzungscookie enthalten.

Was mache ich falsch?

user345625
quelle
2
Nach dem Web-Cookie wird möglicherweise ein Ajax-Cookie angezeigt, und FireBug fängt möglicherweise das Cookie der ersten Seite ab.
Chris
1
Ich habe nicht verstanden, was du meinst, aber ich kann sagen, wenn ich die Anforderungs-URL in die Adressleiste des Browsers einfüge und Firebug erneut überprüfe, kann ich das Cookie in den an den Server gesendeten Headres sehen. Irgendwelche Lösungen?
user345625
Ich denke also, Ajax wird genauso umgehen wie der Browser
user345625
Welchen Code verwenden Sie?
Dean Harding
Der Browser erstellt weiterhin Cookies, die vom Server während einer Ajax-Anfrage, einer Abfrage oder auf andere Weise gesetzt wurden. Haben Sie die Antwort auf die Ajax-Anfrage überprüft und sichergestellt, dass Cookies vom zu setzenden Server zurückkommen? Es könnte ein Problem mit dem Servercode geben, so dass nicht einmal das Cookie usw. gesetzt wird
David

Antworten:

218

AJAX-Anrufe senden nur Cookies, wenn sich die von Ihnen angerufene URL in derselben Domain befindet wie Ihr aufrufendes Skript.

Dies kann ein domänenübergreifendes Problem sein.

Möglicherweise haben Sie versucht, eine URL aufzurufen, www.domain-a.comwährend Ihr Anrufskript aktiviert war www.domain-b.com(Mit anderen Worten: Sie haben einen domänenübergreifenden Anruf getätigt. In diesem Fall hat der Browser keine Cookies gesendet, um Ihre Privatsphäre zu schützen).

In diesem Fall haben Sie folgende Möglichkeiten:

  • Schreiben Sie einen kleinen Proxy, der sich in Domain-b befindet, und leiten Sie Ihre Anfragen an Domain-a weiter. In Ihrem Browser können Sie den Proxy aufrufen, da er sich auf demselben Server befindet wie das aufrufende Skript.
    Dieser Proxy kann dann von Ihnen so konfiguriert werden, dass er einen Cookie-Namen und einen Wertparameter akzeptiert, die er an Domäne-a senden kann. Damit dies funktioniert, müssen Sie den Namen des Cookies kennen und den Wert Ihres Servers auf Domain-A für die Authentifizierung angeben.
  • Wenn Sie JSON-Objekte abrufen, versuchen Sie stattdessen, eine JSONP- Anforderung zu verwenden. jQuery unterstützt diese. Sie müssen Ihren Dienst jedoch auf Domain-a ändern, damit er gültige JSONP-Antworten zurückgibt.

Ich bin froh, wenn das auch nur ein bisschen geholfen hat.

Grippe
quelle
19
Es ist auch erwähnenswert, dass Cookies auf einen bestimmten Pfad gesetzt werden können. Wenn also ein Cookie mit gesetzt wurde path=/somethingund Sie die Seite anfordern, wird /anotherdas Cookie nicht gesendet. Wenn Sie die Seite anfordern, wird /somethingdas Cookie wie erwartet gesendet. Überprüfen Sie also den Code, der auch das Cookie setzt.
Styfle
2
Sendet eine JSONP-Anfrage Coockies?
Albanx
1
@albanx Ja, wenn die von mir genannten Anforderungen festgelegt sind. Es ist nur eine normale Anfrage wie jede andere und sendet als solche Cookies.
Grippe
1
@albanx diese andere verwandte Frage enthält ein Beispiel, wie man diese JSONP-Anfrage mit benutzerdefinierten Cookies macht
AntonioHerraizS
4
Laut JSONP auf Wikipedia> wurde dieser Ansatz zugunsten von CORS
Peter Dotchev
386

Ich arbeite in einem domänenübergreifenden Szenario. Während der Anmeldung gibt der Remote-Server den Set-Cookie-Header zusammen mit Access-Control-Allow-Credentialsset auf true zurück.

Der nächste Ajax-Aufruf an den Remote-Server sollte dieses Cookie verwenden.

CORS Access-Control-Allow-Credentialsermöglicht die domänenübergreifende Protokollierung. Beispiele finden Sie unter https://developer.mozilla.org/En/HTTP_access_control .

Für mich scheint es ein Fehler in JQuery zu sein (oder zumindest eine zukünftige Funktion in der nächsten Version).

AKTUALISIEREN:

  1. Cookies werden nicht automatisch aus der AJAX-Antwort gesetzt (Zitat: http://aleembawany.com/2006/11/14/anatomy-of-a-well-designed-ajax-login-experience/ )

    Warum?

  2. Sie können den Wert des Cookies nicht aus der Antwort abrufen, um ihn manuell festzulegen ( http://www.w3.org/TR/XMLHttpRequest/#dom-xmlhttprequest-getresponseheader ).

    Ich bin verwirrt..

    Es sollte eine Möglichkeit geben, jquery.ajax()nach dem Einstellen von XMLHttpRequest.withCredentials = "true"Parametern zu fragen .

ANTWORT: Sie sollten den xhrFieldsParameter http://api.jquery.com/jQuery.ajax/ verwenden.

Das Beispiel in der Dokumentation lautet:

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

Es ist auch wichtig, dass der Server diese Anfrage korrekt beantwortet. Kopieren Sie hier tolle Kommentare von @ Frédéric und @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: *

Also, wenn die Anfrage lautet:

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

Der Server sollte antworten mit:

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

[payload]

Andernfalls werden die Nutzdaten nicht an das Skript zurückgegeben. Siehe: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials

Kangur
quelle
8
Großartig ! Ich füge hinzu, um diesen + Access-Control-Allow-Credentials-Header auf true auf der Serverseite zu setzen
Frédéric
und wo setze ich diese Anmeldeinformationen? bei der Header-Autorisierung? beim Anforderungshauptteil?
Francisco Corrales Morales
3
Vielen Dank für die Antwort :) Nur eine 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: *
kurze
Nichts davon hat bei mir leider funktioniert. Wenn ich dieselbe Anforderung von AngularJS aus starte, funktioniert sie, aber von jQuery wird das Sitzungscookie trotz dieser Vorschläge nicht übergeben. (jQuery v2.1.1)
geoidesic
(OO) Du hast mich vor verschiedenen schmerzhaften Stunden gerettet. Was für eine perfekte Antwort! Vielen Dank! Ich musste diese im öffentlichen Stammverzeichnis .htaccess meiner Website hinzufügen: <IfModule mod_headers.c> Header-Set Access-Control-Allow-Origin " localhost " Header-Set Access-Control-Allow-Credentials "true" </ IfModule>
Vinay Vissh
48

Verwenden von

xhrFields: { withCredentials:true }

Als Teil meines jQuery-Ajax-Aufrufs war dies nur ein Teil der Lösung. Ich musste auch die Header in der OPTIONS-Antwort von meiner Ressource zurückgeben:

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

Es war wichtig, dass sich nur ein zulässiger "Ursprung" im Antwortheader des OPTIONS-Aufrufs befand und nicht "*". Ich habe dies erreicht, indem ich den Ursprung aus der Anfrage gelesen und wieder in die Antwort eingefügt habe - wahrscheinlich um den ursprünglichen Grund für die Einschränkung herum, aber in meinem Anwendungsfall ist die Sicherheit nicht von größter Bedeutung.

Ich dachte, es lohnt sich, ausdrücklich die Anforderung für nur einen Ursprung zu erwähnen, da der W3C-Standard eine durch Leerzeichen getrennte Liste zulässt - Chrome jedoch nicht! http://www.w3.org/TR/cors/#access-control-allow-origin-response-header NB das "in der Praxis" -Bit.

wombling - Chris Paine
quelle
41

Fügen Sie dies in Ihre Init-Funktion ein:

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

Es wird klappen.

Alex Athlan
quelle
1
Du hast meinen Tag gerettet! Auf Methodenebene hat withCredentials bei mir nicht funktioniert. Aber global funktioniert es endlich! Vielen Dank.
Paulius Matulionis
Seien Sie vorsichtig damit, da es Cookies an alle Anfragen sendet, Ether für andere Domains (was dies nicht erwartet und die Anfrage fehlschlägt, indem Access-Control-Allow-Credentials erforderlich sind)
devi
12

Es gibt bereits viele gute Antworten auf diese Frage, aber ich dachte, es könnte hilfreich sein, den Fall zu klären, in dem Sie erwarten würden, dass das Sitzungscookie gesendet wird, weil die Cookie-Domain übereinstimmt, aber es wird nicht gesendet, weil die AJAX-Anfrage lautet zu einer anderen Subdomain gemacht werden. In diesem Fall habe ich ein Cookie, das der Domain * .mydomain.com zugewiesen ist, und ich möchte, dass es in eine AJAX-Anfrage an different.mydomain.com aufgenommen wird. "Standardmäßig wird das Cookie nicht gesendet. Sie müssen HTTPONLY im Sitzungscookie nicht deaktivieren, um dieses Problem zu beheben. Sie müssen nur die vorgeschlagenen Schritte ausführen ( https://stackoverflow.com/a/23660618/545223 ) und die folgenden Schritte ausführen .

1) Fügen Sie Ihrer Ajax-Anfrage Folgendes hinzu.

xhrFields: { withCredentials:true }

2) Fügen Sie Ihren Antwortheadern Folgendes für Ressourcen in der verschiedenen Subdomain hinzu.

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

Nachdem ich die anderen Lösungen ausprobiert hatte und sie immer noch nicht zum Laufen gebracht hatte, fand ich heraus, wo das Problem in meinem Fall lag. Ich habe contentType von "application / json" in "text / plain" geändert.

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

Ich hatte das gleiche Problem und führte einige Überprüfungen durch, bei denen mein Skript einfach nicht den Sitzungs-ID-Cookie erhielt.

Ich habe anhand des Sitzungs-ID-Cookie-Werts im Browser herausgefunden, dass mein Framework (Django) das Sitzungs-ID-Cookie mit HttpOnly als Standard übergeben hat. Dies bedeutete, dass Skripte keinen Zugriff auf den Wert der Sitzungs-ID hatten und ihn daher nicht zusammen mit Anforderungen weitergaben. Ein bisschen lächerlich, dass HttpOnly der Standardwert ist, wenn so viele Dinge Ajax verwenden, die eine Zugriffsbeschränkung erfordern würden.

Um dies zu beheben, habe ich eine Einstellung geändert (SESSION_COOKIE_HTTPONLY = False), aber in anderen Fällen kann es sich um ein "HttpOnly" -Flag im Cookie-Pfad handeln

wiwa
quelle
2
Mach das nicht. Es ermöglicht dem clientseitigen Skriptzugriff auf das Sitzungscookie, der der häufigste XSS-Angriffsvektor ist. owasp.org/index.php/HttpOnly
Jason Elkin
1

Wenn Sie localhosteinen oder einen Port auf localhost entwickeln, z. B. localhost:8080zusätzlich zu den in den obigen Antworten beschriebenen Schritten, müssen Sie auch sicherstellen, dass Sie keinen Domain-Wert im Set-Cookie-Header übergeben.
Sie können die Domain nicht localhostim Set-Cookie-Header festlegen - das ist falsch - lassen Sie einfach die Domain weg.

Siehe Cookies auf localhost mit expliziter Domain und Warum erstellt asp.net keine Cookies in localhost?

Jitin
quelle
0

Nur meine 2 Cent für das Setzen des PHPSESSID-Cookie-Problems auf localhost und in der Entwicklungsumgebung. Ich rufe AJAX an meinem REST-API-Endpunkt auf dem Locahost auf. mysite.localhost/api/member/login/Angenommen, die Adresse lautet (virtueller Host in meiner Entwicklungsumgebung).

  • Wenn ich diese Anfrage bei Postman mache, läuft alles gut und PHPSESSID wird mit der Antwort festgelegt.

  • Wenn ich diesen Endpunkt über AJAX von der Browsersync-Proxy-Seite anfordere (z. B. 122.133.1.110:3000/test/api/login.phpin der Adresszeile meines Browsers, siehe Domain unterscheidet sich von vs mysite.localhost), wird PHPSESSID unter Cookies nicht angezeigt.

  • Wenn ich diese Anfrage direkt von der Seite in derselben Domain (dh mysite.localhost/test/api/login.php) mache, ist PHPSESSID in Ordnung.

Dies ist also ein Problem mit Cookies für Ursprungsanfragen, wie in der obigen Antwort von @flu erwähnt

Valentine Shi
quelle
0

Hinzufügen meines Szenarios und meiner Lösung für den Fall, dass es jemand anderem hilft. Bei der Verwendung von RESTful-APIs ist ein ähnlicher Fall aufgetreten. Mein Webserver, auf dem HTML- / Skript- / CSS-Dateien gehostet werden, und Application Server-Exposure-APIs wurden in derselben Domäne gehostet. Der Weg war jedoch anders.

Webserver - mydomain / Webseiten /abc.html

benutzte abc.js, die den Cookie mycookie setzten

App-Server - mydomain / webapis / servicename.

zu denen API-Anrufe gemacht wurden

Ich habe den Cookie in mydomain / webapis / servicename erwartet und versucht, ihn zu lesen, aber er wurde nicht gesendet. Nachdem ich den Kommentar aus der Antwort gelesen hatte, überprüfte ich im Entwicklungstool des Browsers, dass der Pfad von mycookie auf "/ webpages " gesetzt war und daher im Serviceabruf nicht verfügbar war

mydomain / webapis / servicename

Während ich Cookies von jquery setze, habe ich Folgendes getan:

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

Vielleicht nicht zu 100% auf die Frage beantwortet, aber ich bin auf diesen Thread gestoßen, in der Hoffnung, ein Sitzungsproblem zu lösen, als ich eine Datei vom Asset Manager des innovastudio-Editors hochgeladen habe. Schließlich war die Lösung einfach: Sie haben einen Flash-Uploader. Deaktivieren Sie dies (Einstellung

var flashUpload = false;   

in asset.php) und die Lichter fingen wieder an zu blinken.

Da diese Probleme sehr schwer zu debuggen sein können, habe ich festgestellt, dass Sie (in diesem Fall ich) auf dem richtigen Weg sind, wenn Sie Folgendes in den Upload-Handler einfügen:

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

Ein Sprung in das Protokoll und ich entdeckte schnell die fehlende Sitzung, in der kein Cookie gesendet wurde.

Ellert van Koperen
quelle
Ich glaube nicht, dass das obige Beispiel funktionieren würde, denn wenn es keinen Sitzungscookie gibt, wie hoch wäre der Wert von $ sn? (zufällig oder vielleicht null), alternativ könnten Benutzer den Sitzungsnamen aus einem GET-Wert festlegen, zum Beispiel auf session_name(isset($_GET['sess']) ? $_GET['sess'] : null);session_start();diese Weise, sie würden eine funktionierende Sache bekommen
Steel Brain
Genau so habe ich das Problem gefunden: Keine Sitzung beim Posten von diesem Flash-Uploader-Ding. Da die Verwendung einer GET-Variablen-Sitzungskennung eine schlechte Idee ist und der Cookie nicht funktioniert hat, habe ich ihn verworfen. Wen kümmert es, Flash gehört sowieso der Vergangenheit an.
Ellert van Koperen