¿Por qué el método .ajax () de jquery no envía mi cookie de sesión?

338

Después de iniciar sesión en $.ajax()un sitio, intento enviar una segunda $.ajax()solicitud a ese sitio, pero cuando verifico los encabezados enviados con FireBug, no se incluye ninguna cookie de sesión en la solicitud.

¿Qué estoy haciendo mal?

usuario345625
fuente
2
La cookie de ajax puede aparecer después de la cookie web y FireBug puede capturar la cookie de la primera página.
Chris
1
No entendí lo que quieres decir, pero puedo decir que si pego la URL de solicitud en la barra de direcciones del navegador y verifico nuevamente Firebug, puedo ver la cookie en los encabezados enviados al servidor. ¿Alguna solución?
user345625
Entonces, creo que ajax también se manejará de la misma manera que lo hace el navegador
usuario345625
¿Cuál es el código que estás usando?
Dean Harding
el navegador seguirá creando cookies establecidas por el servidor durante una solicitud ajax, jquery o de otra manera. ¿Verificó la respuesta a la solicitud de ajax y se aseguró de que las cookies regresaron del servidor para ser configuradas? Podría haber un problema con el código del servidor de tal manera que ni siquiera está configurando la cookie, etc.
David

Respuestas:

218

Las llamadas AJAX solo envían cookies si la url a la que llama está en el mismo dominio que su script de llamada.

Esto puede ser un problema de dominio cruzado.

Tal vez trató de llamar a una URL desde www.domain-a.comque su script de llamada estaba activado www.domain-b.com(en otras palabras: realizó una llamada entre dominios, en cuyo caso el navegador no enviará ninguna cookie para proteger su privacidad).

En este caso, sus opciones son:

  • Escriba un pequeño proxy que resida en el dominio-b y reenvíe sus solicitudes al dominio-a. Su navegador le permitirá llamar al proxy porque está en el mismo servidor que el script de llamada.
    Usted puede configurar este proxy para que acepte un nombre de cookie y un parámetro de valor que puede enviar al dominio-a. Pero para que esto funcione, necesita saber el nombre de la cookie y valorar su servidor en el dominio-a quiere autenticación.
  • Si está buscando objetos JSON, intente utilizar una solicitud JSONP en su lugar. jQuery es compatible con estos. Pero debe alterar su servicio en el dominio-a para que devuelva respuestas JSONP válidas.

Me alegro si eso ayudó incluso un poco.

gripe
fuente
19
También vale la pena señalar que las cookies se pueden establecer en una ruta específica, por lo que si su cookie se configuró path=/somethingy está solicitando la página/another , la cookie no se enviará. Cuando solicite la página, /somethingla cookie se enviará como se esperaba. Así que verifique también el código que establece la cookie.
styfle
2
¿Una solicitud de JSONP envía coockies?
albanx
1
@albanx Sí, si se establecen los requisitos que mencioné. Es solo una solicitud normal como cualquier otra y, como tal, envía cookies.
gripe
1
@albanx esta otra pregunta relacionada incluye un ejemplo de cómo hacer esa solicitud JSONP con cookies personalizadas
AntonioHerraizS
44
De acuerdo con JSONP en Wikipedia> este enfoque fue abandonado a favor de CORS
Peter Dotchev
388

Estoy operando en un escenario de dominio cruzado. Durante el inicio de sesión, el servidor remoto devuelve el encabezado Set-Cookie junto con Access-Control-Allow-Credentialsset a true.

La próxima llamada ajax al servidor remoto debe usar esta cookie.

CORS Access-Control-Allow-Credentialsestá ahí para permitir el registro entre dominios. Consulte https://developer.mozilla.org/En/HTTP_access_control para ver ejemplos.

Para mí, parece un error en JQuery (o al menos característica en la próxima versión).

ACTUALIZAR:

  1. Las cookies no se configuran automáticamente a partir de la respuesta AJAX (cita: http://aleembawany.com/2006/11/14/anatomy-of-a-well-designed-ajax-login-experience/ )

    ¿Por qué?

  2. No puede obtener el valor de la cookie de la respuesta para configurarla manualmente ( http://www.w3.org/TR/XMLHttpRequest/#dom-xmlhttprequest-getresponseheader )

    Estoy confundido..

    Debería existir una manera de pedir jquery.ajax()establecer el XMLHttpRequest.withCredentials = "true"parámetro.

RESPUESTA: Debes usar el xhrFieldsparámetro de http://api.jquery.com/jQuery.ajax/

El ejemplo en la documentación es:

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

También es importante que el servidor responda correctamente a esta solicitud. Copiando aquí excelentes comentarios de @ Frédéric y @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: *

Entonces, cuando la solicitud es:

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

El servidor debe responder con:

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

[payload]

De lo contrario, la carga útil no se devolverá al script. Ver: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials

Kangur
fuente
8
Excelente ! Agrego para usar este + conjunto de encabezado Access-Control-Allow-Credentials a verdadero en el lado del servidor
Frédéric
¿y dónde configuro esas Credenciales ?, ¿en la Autorización de encabezado ?, ¿en el cuerpo de la solicitud?
Francisco Corrales Morales
3
Gracias por la respuesta :) solo una adición rápida, puede valer la pena mencionar 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
Nada de esto me funcionó desafortunadamente. Si ejecuto la misma solicitud de AngularJS, funciona, pero desde jQuery, incluso con estas sugerencias, la cookie de sesión no se pasa. (jQuery v2.1.1)
geodésico
(OO) Me salvaste de varias horas dolorosas. ¡Qué respuesta perfecta! ¡Gracias! Necesitaba agregarlos en la raíz pública .htaccess de mi sitio web: <IfModule mod_headers.c> Conjunto de encabezado Access-Control-Allow-Origin " localhost " Conjunto de encabezado Access-Control-Allow-Credentials "true" </IfModule>
Vinay Vissh
48

Utilizando

xhrFields: { withCredentials:true }

Como parte de mi llamada jQuery ajax fue solo parte de la solución. También necesitaba que me devolvieran los encabezados en la respuesta OPTIONS de mi recurso:

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

Era importante que solo un "origen" permitido estuviera en el encabezado de respuesta de la llamada OPTIONS y no "*". Lo logré leyendo el origen de la solicitud y llenándolo nuevamente a la respuesta, probablemente eludiendo la razón original de la restricción, pero en mi caso de uso la seguridad no es primordial.

Pensé que valía la pena mencionar explícitamente el requisito de un solo origen, ya que el estándar W3C permite una lista separada por espacios, ¡pero Chrome no lo hace! http://www.w3.org/TR/cors/#access-control-allow-origin-response-header NB el bit "en la práctica".

wombling - Chris Paine
fuente
41

Pon esto en tu función init:

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

Funcionará.

Alex Athlan
fuente
1
¡Salvaste mi día! En el nivel de método con credenciales no funcionó para mí. ¡Pero globalmente como este finalmente funciona! Gracias.
Paulius Matulionis
tenga cuidado con esto, ya que enviará cookies a todas las solicitudes, éter para otros dominios (que no se espera esto y falla la solicitud por requerir Access-Control-Allow-Credentials)
gdbdable
12

Ya hay muchas buenas respuestas a esta pregunta, pero pensé que podría ser útil aclarar el caso en el que esperaría que se envíe la cookie de sesión porque el dominio de la cookie coincide, pero no se envía porque la solicitud AJAX es siendo hecho a un subdominio diferente. En este caso, tengo una cookie que está asignada al dominio * .midominio.com , y deseo que se incluya en una solicitud AJAX a different.mydomain.com ". Por defecto, la cookie no se envía. No necesita deshabilitar HTTPONLY en la cookie de sesión para resolver este problema. Solo necesita hacer lo que sugiere wombling ( https://stackoverflow.com/a/23660618/545223 ) y hacer lo siguiente.

1) Agregue lo siguiente a su solicitud de ajax.

xhrFields: { withCredentials:true }

2) Agregue lo siguiente a sus encabezados de respuesta para los recursos en los diferentes subdominios.

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

Después de probar las otras soluciones y aún no lograr que funcionara, descubrí cuál era el problema en mi caso. Cambié contentType de "application / json" a "text / plain".

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

Estaba teniendo el mismo problema y haciendo algunas comprobaciones mi script simplemente no estaba recibiendo la cookie sessionid.

Al observar el valor de la cookie de sessionid en el navegador, descubrí que mi framework (Django) estaba pasando la cookie de sessionid con HttpOnly como predeterminado. Esto significaba que los scripts no tenían acceso al valor de sessionid y, por lo tanto, no lo pasaban junto con las solicitudes. Es ridículo que HttpOnly sea el valor predeterminado cuando tantas cosas usan Ajax que requerirían restricción de acceso.

Para solucionar esto, cambié una configuración (SESSION_COOKIE_HTTPONLY = False) pero en otros casos puede ser un indicador "HttpOnly" en la ruta de la cookie

wiwa
fuente
2
No hagas esto. Permite el acceso del script del lado del cliente a la cookie de sesión, que es el vector de ataque XSS más común. owasp.org/index.php/HttpOnly
Jason Elkin
0

Solo mis 2 centavos para configurar el problema de cookies PHPSESSID cuando estoy en localhost y en un entorno de desarrollo. Realizo la llamada AJAX a mi punto final API REST en el host local. Digamos que su dirección es mysite.localhost/api/member/login/(host virtual en mi entorno de desarrollo).

  • Cuando hago esta solicitud en Postman , las cosas van bien y PHPSESSID se configura con la respuesta.

  • Cuando solicito este punto final a través de AJAX desde la página proxy de Browsersync (por ejemplo, 122.133.1.110:3000/test/api/login.phpen la línea de dirección de mi navegador, veo que el dominio es diferente vs mysite.localhost) PHPSESSID no aparece entre las cookies.

  • Cuando realizo esta solicitud directamente desde la página en el mismo dominio (es decir mysite.localhost/test/api/login.php), PHPSESSID está configurado correctamente.

Entonces, este es un problema de cookies de solicitud de origen de origen cruzado como se menciona en la respuesta @flu anterior

Valentine Shi
fuente
0

Agregar mi escenario y solución en caso de que ayude a alguien más. Encontré un caso similar al usar API RESTful. Mi servidor web que alojaba archivos HTML / Script / CSS y el servidor de aplicaciones que exponía API estaban alojados en el mismo dominio. Sin embargo, el camino era diferente.

servidor web: midominio / páginas web /abc.html

utiliza abc.js que establece la cookie llamada mycookie

servidor de aplicaciones: midominio / webapis / servicename.

a lo que se hicieron llamadas API

Esperaba la cookie en mydomain / webapis / servicename e intenté leerla pero no se estaba enviando. Después de leer el comentario de la respuesta, verifiqué en la herramienta de desarrollo del navegador que la ruta de mycookie estaba configurada en "/ páginas web " y, por lo tanto, no estaba disponible en la llamada de servicio para

midominio / webapis / servicename

Entonces, al configurar la cookie desde jquery, esto es lo que hice:

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

Tal vez no responda al 100% a la pregunta, pero me topé con este hilo con la esperanza de resolver un problema de sesión cuando publico una carga de archivo desde el administrador de activos del editor innovastudio. Finalmente, la solución fue simple: tienen un cargador de flash. Deshabilitar eso (configuración

var flashUpload = false;   

en asset.php) y las luces comenzaron a parpadear nuevamente.

Como estos problemas pueden ser muy difíciles de depurar, descubrí que poner algo como lo siguiente en el controlador de carga lo colocará (en este caso, a mí) en el camino correcto:

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

Me sumergí en el registro y rápidamente vi la sesión perdida, donde no se envió ninguna cookie.

Ellert van Koperen
fuente
No creo que el ejemplo anterior funcione, porque cuando no hay una cookie de sesión, ¿cuál sería el valor de $ sn? (uno aleatorio, o tal vez nulo), alternativamente, los usuarios podrían establecer session_name a partir de un valor GET, por ejemplo, de session_name(isset($_GET['sess']) ? $_GET['sess'] : null);session_start();esta manera, obtendrían algo que funciona
Steel Brain
Así es exactamente como encontré el problema: no hay sesión al publicar desde este cargador flash. Como usar un identificador de sesión variable GET es una mala idea, y la cookie no funcionaba, la descarté. A quién le importa, de todos modos, el flash es cosa del pasado.
Ellert van Koperen