Por que o método .ajax () do jquery não está enviando meu cookie de sessão?

338

Depois de fazer login em $.ajax()um site, estou tentando enviar uma segunda $.ajax()solicitação para esse site - mas quando verifico os cabeçalhos enviados usando o FireBug, não há nenhum cookie de sessão sendo incluído na solicitação.

O que estou fazendo errado?

user345625
fonte
2
O cookie do ajax pode vir após o cookie da Web e o FireBug pode capturar o cookie da primeira página.
Chris
11
Eu não entendi o que você quer dizer, mas posso dizer que se colar o URL da solicitação na barra de endereços do navegador e verificar o Firebug novamente, posso ver o cookie nos cabeçalhos enviados ao servidor. Alguma solução?
User345625
Então, eu acho ajax também irá lidar com mesmo navegador maneira faz
user345625
Qual é o código que você está usando?
Dean Harding
o navegador ainda criará cookies configurados pelo servidor durante uma solicitação ajax, jquery ou outro. Você verificou a resposta à solicitação do ajax e garantiu que os cookies voltassem do servidor para serem configurados? Não poderia haver um problema com o código do servidor de tal forma que nem sequer é definir o cookie, etc.
David

Respostas:

218

As chamadas AJAX apenas enviam cookies se o URL que você está chamando estiver no mesmo domínio que o seu script de chamada.

Este pode ser um problema entre domínios.

Talvez você tenha tentado ligar para um URL www.domain-a.comenquanto o script de chamada estava ativado www.domain-b.com(em outras palavras: você fez uma chamada entre domínios; nesse caso, o navegador não envia cookies para proteger sua privacidade).

Nesse caso, suas opções são:

  • Escreva um pequeno proxy que resida no domínio-b e encaminhe suas solicitações para o domínio-a. Seu navegador permitirá que você chame o proxy porque está no mesmo servidor que o script de chamada.
    Esse proxy pode então ser configurado por você para aceitar um nome de cookie e um parâmetro de valor que pode ser enviado ao domínio-a. Mas, para que isso funcione, você precisa saber o nome do cookie e avaliar seu servidor no domínio - a quer autenticação.
  • Se você estiver buscando objetos JSON, tente usar uma solicitação JSONP . O jQuery suporta isso. Mas você precisa alterar seu serviço no domínio-a para que ele retorne respostas JSONP válidas.

Ainda bem que isso ajudou um pouco.

gripe
fonte
19
Também é importante notar que os cookies podem ser configurados para um caminho específico; portanto, se você definiu o cookie path=/somethinge está solicitando a página /another, o cookie não será enviado. Quando você solicita a página, /somethingo cookie será enviado conforme o esperado. Portanto, verifique o código que define o cookie também.
styfle
2
uma solicitação jsonp envia coockies?
albanx
11
@ albanx Sim, se os requisitos que eu mencionei estiverem definidos. É apenas uma solicitação normal como qualquer outra e, como tal, envia cookies.
flu
11
@albanx esta outra questão relacionada inclui um exemplo de como fazer essa solicitação JSONP com cookies personalizados
AntonioHerraizS
4
De acordo com JSONP em Wikipedia> esta abordagem foi abandonada em favor de CORS
Peter Dotchev
387

Estou operando no cenário entre domínios. Durante o login, o servidor remoto está retornando o cabeçalho Set-Cookie junto com Access-Control-Allow-Credentialsset como true.

A próxima chamada ajax para o servidor remoto deve usar esse cookie.

Os CORS Access-Control-Allow-Credentialsestão lá para permitir o registro entre domínios. Verifique https://developer.mozilla.org/En/HTTP_access_control para obter exemplos.

Para mim, parece um bug no JQuery (ou pelo menos um recurso na próxima versão).

ATUALIZAR:

  1. Os cookies não são definidos automaticamente a partir da resposta AJAX (citação: http://aleembawany.com/2006/11/14/anatomy-of-a-well-designed-ajax-login-experience/ )

    Por quê?

  2. Você não pode obter o valor do cookie da resposta para defini-lo manualmente ( http://www.w3.org/TR/XMLHttpRequest/#dom-xmlhttprequest-getresponseheader )

    Estou confuso..

    Deve haver uma maneira de pedir jquery.ajax()para definir o XMLHttpRequest.withCredentials = "true"parâmetro.

RESPOSTA: Você deve usar o xhrFieldsparâmetro http://api.jquery.com/jQuery.ajax/

O exemplo na documentação é:

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

Também é importante que o servidor responda corretamente a essa solicitação. Copiando aqui ótimos comentários de @ Frédéric e @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: *

Então, quando a solicitação é:

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

O servidor deve responder com:

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

[payload]

Caso contrário, a carga útil não será retornada ao script. Consulte: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials

Kangur
fonte
8
Ótimo ! Acrescento para usar esta + set Access-Control-Allow-Credenciais cabeçalho para true no lado do servidor
Frédéric
e onde eu defino essas credenciais?, na Autorização de cabeçalho?, no corpo da solicitação?
Francisco Corrales Morales
3
Obrigado pela resposta :) apenas uma adição rápida, pode valer a 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
Infelizmente, nada disso funcionou para mim. Se eu executar o mesmo pedido do AngularJS, ele funciona, mas do jQuery, mesmo com essas sugestões, a sessão Cookie não é passada. (jQuery v2.1.1)
geoidesic
(OO) Você me salvou de várias horas dolorosas. Que resposta perfeita! Obrigado! Eu precisava adicioná-los na raiz pública .htaccess do meu site: <IfModule mod_headers.c> Conjunto de cabeçalhos Access-Control-Allow-Origin " localhost " Conjunto de cabeçalhos Access-Control-Allow-Credentials "true" </IfModule>
Vinay Vissh
48

Usando

xhrFields: { withCredentials:true }

como parte da minha chamada jQuery ajax era apenas parte da solução. Eu também precisava ter os cabeçalhos retornados na resposta OPTIONS do meu recurso:

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

Era importante que apenas uma "origem" permitida estivesse no cabeçalho de resposta da chamada OPTIONS e não "*". Consegui isso lendo a origem da solicitação e preenchendo-a novamente na resposta - provavelmente contornando o motivo original da restrição, mas, no meu caso de uso, a segurança não é fundamental.

Eu pensei que vale a pena mencionar explicitamente o requisito para apenas uma origem, pois o padrão W3C permite uma lista separada por espaço - mas o Chrome não! http://www.w3.org/TR/cors/#access-control-allow-origin-response-header NB o bit "na prática".

wombling - Chris Paine
fonte
41

Coloque isso na sua função init:

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

Vai funcionar.

Alex Athlan
fonte
11
Você salvou meu dia! No nível do método withCredentials, não funcionou para mim. Mas globalmente assim, finalmente funciona! Obrigado.
Paulius Matulionis
ter cuidado com ele, porque ele irá enviar cookies para todas as solicitações, éter para outros domínios (que não é de esperar isso e deixar pedido exigir credenciais de Access-Control-Allow-)
gdbdable
12

Já existem muitas respostas boas para essa pergunta, mas achei útil esclarecer o caso em que você espera que o cookie da sessão seja enviado porque o domínio do cookie corresponde, mas não está sendo enviado porque a solicitação AJAX é sendo feito para um subdomínio diferente. Nesse caso, tenho um cookie atribuído ao domínio * .mydomain.com e pretendo que ele seja incluído em uma solicitação AJAX para different.mydomain.com ". Por padrão, o cookie não é enviado. Você não precisa desabilitar o HTTPONLY no cookie da sessão para resolver esse problema. Você só precisa fazer o que sugeriu wombling ( https://stackoverflow.com/a/23660618/545223 ) e fazer o seguinte.

1) Adicione o seguinte ao seu pedido de ajax.

xhrFields: { withCredentials:true }

2) Adicione o seguinte aos seus cabeçalhos de resposta para obter recursos nos diferentes subdomínios.

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

Depois de experimentar as outras soluções e ainda não fazê-lo funcionar, descobri qual era o problema no meu caso. Alterei contentType de "application / json" para "text / plain".

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

Eu estava tendo o mesmo problema e, ao fazer algumas verificações, meu script simplesmente não estava recebendo o cookie sessionid.

Eu descobri olhando para o valor do cookie sessionid no navegador que minha estrutura (Django) estava passando o cookie sessionid com o HttpOnly como padrão. Isso significava que os scripts não tinham acesso ao valor sessionid e, portanto, não o passavam junto com os pedidos. É ridículo que HttpOnly seja o valor padrão quando tantas coisas usam o Ajax, o que exigiria restrição de acesso.

Para corrigir isso, alterei uma configuração (SESSION_COOKIE_HTTPONLY = False), mas em outros casos pode ser um sinalizador "HttpOnly" no caminho do cookie

wiwa
fonte
2
Não faça isso. Ele permite que o script do lado do cliente acesse o cookie da sessão, que é o vetor de ataque XSS mais comum. owasp.org/index.php/HttpOnly
Jason Elkin
1

Se você estiver desenvolvendo em localhostou uma porta no host local, como localhost:8080, além das etapas descritas nas respostas acima, também precisará garantir que não esteja passando um valor de domínio no cabeçalho Set-Cookie.
Você não pode definir o domínio localhostno cabeçalho Set-Cookie - isso está incorreto - apenas omita o domínio.

Veja Cookies no host local com domínio explícito e Por que o asp.net não cria cookies no host local?

jitin
fonte
0

Apenas meus 2 centavos na configuração do problema de cookie PHPSESSID quando estiver no host local e no ambiente de desenvolvimento. Eu faço a chamada AJAX para o meu ponto de extremidade da API REST no locahost. Digamos que seu endereço seja mysite.localhost/api/member/login/(host virtual no meu ambiente de desenvolvimento).

  • Quando faço essa solicitação no Postman , as coisas correm bem e o PHPSESSID é definido com a resposta.

  • Quando solicito esse endpoint via AJAX na página em proxy do Browsersync (por exemplo, 122.133.1.110:3000/test/api/login.phpna linha de endereço do meu navegador, veja se o domínio é diferente mysite.localhost), o PHPSESSID não aparece entre os cookies.

  • Quando faço esse pedido diretamente da página no mesmo domínio (por exemplo mysite.localhost/test/api/login.php), o PHPSESSID está definido corretamente.

Portanto, este é um problema de cookies de solicitação de origem de origem cruzada, conforme mencionado na resposta @flu acima

Valentine Shi
fonte
0

Adicionando meu cenário e solução, caso isso ajude outra pessoa. Encontrei um caso semelhante ao usar APIs RESTful. Meu servidor da Web que hospeda arquivos HTML / Script / CSS e APIs de exposição do Application Server foram hospedados no mesmo domínio. No entanto, o caminho foi diferente.

servidor web - meudomínio / páginas da web /abc.html

usou o abc.js que define o cookie chamado mycookie

servidor de aplicativos - meudominio / webapis / servicename.

para o qual as chamadas da API foram feitas

Eu estava esperando o cookie em meudomínio / webapis / servicename e tentei lê-lo, mas ele não estava sendo enviado. Depois de ler o comentário da resposta, verifiquei na ferramenta de desenvolvimento do navegador que o caminho do mycookie estava definido como "/ páginas da web " e, portanto, não estava disponível na chamada de serviço para

mydomain / webapis / servicename

Então, ao definir o cookie do jquery, foi o que eu fiz -

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

Talvez não esteja 100% respondendo à pergunta, mas me deparei com esse tópico na esperança de resolver um problema de sessão ao postar ajax um upload de arquivo do gerenciador de ativos do editor innovastudio. Eventualmente, a solução foi simples: eles têm um flash-uploader. Desativando isso (configuração

var flashUpload = false;   

em asset.php) e as luzes começaram a piscar novamente.

Como esses problemas podem ser muito difíceis de depurar, descobri que colocar algo como o seguinte no manipulador de upload definirá você (bem, eu neste caso) no caminho certo:

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

Mergulhei no registro e rapidamente localizei a sessão ausente, onde nenhum cookie foi enviado.

Ellert van Koperen
fonte
Eu não acho que o exemplo acima funcionaria, porque quando não há cookie de sessão, qual seria o valor de $ sn? (um acaso, ou talvez nulo), alternativamente, os usuários podem definir session_name de um valor GET por exemplo session_name(isset($_GET['sess']) ? $_GET['sess'] : null);session_start();desta forma, eles teriam uma coisa trabalhando
Aço Cérebro
Foi exatamente assim que encontrei o problema: nenhuma sessão ao postar algo desse carregador de flash. Como usar um identificador de sessão variável GET é uma má idéia, e o cookie não estava funcionando, eu joguei fora. Quem se importa, o flash é uma coisa do passado de qualquer maneira.
Ellert van Koperen