Sair: GET ou POST?

435

Esta questão não é sobre quando usar GET ou POST em geral; é sobre qual é o recomendado para lidar com o logoff de um aplicativo da web. Encontrei muitas informações sobre as diferenças entre GET e POST no sentido geral, mas não encontrei uma resposta definitiva para esse cenário em particular.

Como pragmático, estou inclinado a usar o GET, porque implementá-lo é muito mais simples que o POST; basta soltar um link simples e pronto. Esse parece ser o caso da grande maioria dos sites em que consigo pensar, pelo menos do alto da minha cabeça. Até o Stack Overflow lida com o logout com GET.

O que me fez hesitar é o argumento (embora antigo) de que alguns aceleradores / proxies da Web pré-armazenam em cache as páginas acessando e recuperando todos os links encontrados na página, para que o usuário obtenha uma resposta mais rápida ao clicar nelas. Não tenho certeza se isso ainda se aplica, mas, se esse fosse o caso, em teoria, um usuário com um desses aceleradores seria expulso do aplicativo assim que efetuar o login, porque o acelerador encontraria e recuperaria o logout mesmo que ela nunca tenha clicado nele.

Tudo o que li até agora sugere que o POST deve ser usado para "ações destrutivas", enquanto as ações que não alteram o estado interno da consulta do aplicativo - como essas - devem ser tratadas com GET . Com base nisso, a verdadeira questão aqui é:

O logoff de um aplicativo é considerado uma ação destrutiva / altera o estado interno do aplicativo?

Daniel Liuzzi
fonte
Bem, supondo que você esteja visitando o site pela primeira vez e o link de logout não estiver presente, você será desconectado ao fazer o login. Seria bom depois que você efetuou login pela segunda vez, já que o URL de logout já está armazenado em cache. Mas pode-se supor que qualquer acelerador decente seria capaz de filtrar a maioria dos URLs de logout.
HyperCas 19/08
2
HyperCas, aceleradores que filtravam os URLs de logout era uma teoria que eu estava considerando e um dos motivos pelos quais decidi postar a pergunta. Sinto-me um pouco relutante em confiar apenas na lógica do acelerador e um dia um usuário com um acelerador de baixa qualidade reclama que não pode fazer login. Você sabe se eles seguem um padrão ou se esse padrão existe?
Daniel Liuzzi
Qualquer acelerador que enviasse um formulário automaticamente (por exemplo) seria IMO de malware ... é totalmente ilógico pensar que um acelerador enviasse um formulário automaticamente. Imagine que você visita o Google. Como ele pôde enviar o formulário de pesquisa? Ninguém pode responder pelo malware, pois é imprevisível demais e não segue as regras.
Alex19 de
3
@ AlexW - Acho que você não entendeu minha pergunta. O cenário do acelerador que propus é mostrar um possível problema ao usar o GET, não o POST, portanto não haveria forma de postagem, apenas links simples que os aceleradores não teriam problemas a seguir.
precisa
1
Sei que estou anos atrasado para isso, mas Alex, não é sobre isso que Daniel está perguntando. Ele está dizendo que se um usuário clicar em um link de logoff e um acelerador retornar a página de logon em cache sem que ele atinja o aplicativo, o usuário permanecerá conectado. Nada a ver com malware, embora a verificação de uma sequência de caracteres User-Agent da FYI não conserte qualquer coisa de qualquer maneira.
Rob Grant

Respostas:

476

Use POST.

Em 2010, o uso GETfoi provavelmente uma resposta aceitável. Mas hoje (em 2013), os navegadores buscarão previamente as páginas que eles "acham" que você visitará a seguir.

Aqui está um dos desenvolvedores do StackOverflow falando sobre esse problema no twitter:

Gostaria de agradecer ao meu banco por fazer o logoff de uma solicitação GET e à equipe do Chrome pela pré-busca prática de URLs. - Nick Craver ( @Nick_Craver ) 29 de janeiro de 2013

Curiosidade: StackOverflow costumava lidar com o logout via GET, mas não mais.

David Murdoch
fonte
2
Obrigado por esta atualização, Dave. Eu nem percebi que a SO trocou o logout para o POST e, sinceramente, não fazia ideia de que o Chrome vem com a pré-busca incorporada. Finalmente, o twit que você citou nunca poderia oferecer um exemplo melhor para o problema que descrevi no meu minha pergunta e confirma minhas suspeitas. Estou votando sua resposta e fazendo dela a resposta aceita.
Daniel Liuzzi
4
No meu navegador, o logout do Stackoverflow parece com <li> <a href="https://stackoverflow.com/users/logout"> logout </a> </li> que é um GET, não um POST #
boatcoder
9
@ Mark0978, clique no link.
David Murdoch
2
Interessante. Esse é provavelmente um dos meus recursos menos favoritos, um logout que me pergunta se tenho certeza. Acho que isso evita que a pré-busca faça o logout, mas Amazon, Ebay e Gmail usam GET para logout sem essa página de truque entre o que o usuário diz que é logout e o evento de logout real. Eu imaginaria que entre as páginas levaria muitas pessoas a acreditarem erroneamente que estavam desconectadas. Os problemas com isso no SO são mínimos, não há dinheiro envolvido e 99% de tudo é público de qualquer maneira.
boatcoder
7
@Red De acordo com o padrão HTTP / 1.1, a culpa é do servidor, não do navegador. Espera-se que GET não tenha efeitos colaterais no lado do servidor. O padrão ainda diz "o usuário não solicitou os efeitos colaterais, portanto, não pode ser responsabilizado por eles".
eyuelt
45

No REST, não deve haver sessão; portanto, não há nada para destruir. Um cliente REST é autenticado em cada solicitação. Entrar ou sair, é apenas uma ilusão.

O que você realmente está perguntando é se o navegador deve continuar enviando as informações de autenticação em cada solicitação.

Indiscutivelmente, se o seu aplicativo criar a ilusão de estar logado, você poderá "sair" usando javascript. Não é necessário ida e volta.


Dissertação de Campo - Seção 5.1.3

cada solicitação do cliente para o servidor deve conter todas as informações necessárias para entender a solicitação e não pode tirar proveito de nenhum contexto armazenado no servidor. O estado da sessão é, portanto, mantido inteiramente no cliente

Darrel Miller
fonte
1
Na verdade, eu não estava ciente disso. Então eu acho que meu aplicativo não será muito RESTful em tudo, como eu estou usando ASP.NET MVC com FormsAuthentication e se baseia em sessões ...
Daniel Liuzzi
19
mas na prática a informação de login é mantida em um cookie marcado com o httponlyatributo para evitar alguns riscos XSS, o que significa que só pode ser reposto a partir do servidor (abreviação de limpar manualmente o cookie)
Remus Rusanu
6
'Manual', como no usuário, acessa as configurações do navegador e escolhe a opção 'Limpar cookies'. Dificilmente é uma maneira aceitável de fazer logoff de um site.
Remus Rusanu
1
@Remus Ahhh, como o ilustre navegador da web torna a escrita de aplicativos da web tão dolorosa.
Darrel Miller
1
@DarrelMiller sim, no entanto, não revogar uma JWT no lado do servidor é uma vulnerabilidade de segurança. Mesmo se os tokens não estiverem armazenados no servidor, eles deverão estar na lista negra quando um usuário desconectar / alterar senhas / alterar funções / encerrar / etc para evitar abusos (pelo menos até que expirem).
Java-addict301 15/05/19
39

Uma maneira de GETser abusada aqui é que uma pessoa (concorrente talvez :) colocou uma tag de imagem com src="<your logout link>"QUALQUER LUGAR na Internet e, se um usuário do seu site topar com essa página, ele será desconectado.

Raveren
fonte
4
Não, isso não está certo. Um link de logoff funcionará apenas se os dados corretos do cookie forem enviados, o que não será de outro domínio. E mesmo se o ID da sessão estiver armazenado no URL, isso também não funcionaria, pois eles mudam para cada sessão.
Richard H
4
Uau, eu nunca pensei nisso! Portanto, existe outro motivo para não usar GET, e outro motivo para não entender por que todo mundo faz isso. Droga, agora estou temped para incluir uma stackoverflow.com/users/logout "imagem" muito meu post e ver o que acontece :-D
Daniel Liuzzi
24
src = é uma solicitação simples do navegador, não vem do lado do servidor, mas do cliente. Ele carrega todos os cookies e vem do IP do usuário. É por isso que os pixels de rastreamento de anúncios funcionam. A única maneira de determinar essa exploração seria verificar o referenciador.
raveren
12
O SuperLogout.com faz exatamente isso (carrega /logoutURLs em imagens ocultas) e funciona.
Dan Dascalescu 28/01
9
re: SuperLogout ... Não sei por que cliquei nisso.
MI Wright
21

Para ser correto, GET / POST (ou outros verbos) são ações em algum recurso (endereçado por URL) - portanto, geralmente trata-se do estado do recurso e não do estado do aplicativo como tal. Portanto, com espírito de verdade, você deve ter um URL como [host name]\[user name]\session, 'DELETE' seria o verbo correto para a ação de logout.

Usar [host name]\bla bla\logoutcomo URL não é realmente um caminho completo REST (IMO), então por que debater sobre o uso correto de GET / POST nele?

Obviamente, eu também uso GET em um URL de logout em meus aplicativos :-)

VinayC
fonte
2
Nesse caso, eu argumentaria que ter o [nome do usuário] parte da URL parece desnecessário, pois os usuários sempre desconectam (ex: DELETE) de sua própria sessão; nunca outros utilizadores :-)
Daniel Liuzzi
1
Na verdade, não - estamos dizendo que a sessão é um recurso e queremos excluí-lo. Portanto, para endereçar uniformemente qualquer sessão, você precisa ter o nome de usuário como parte da URL. Seu argumento é tão bom quanto dizer que emitir ação PUT em [galeria de fotos] \ fotos significa que você está adicionando às suas fotos (disponível em [galeria de fotos] \ [nome do usuário] \ fotos). Recursos diferentes precisam ser abordados explicitamente, não pode haver nenhuma implicação nele. O site pode permitir que outros usuários adicionem fotos à sua galeria - isso faria parte do controle de acesso, assim como você pode ter um superusuário que pode matar as sessões de qualquer pessoa.
VinayC
1
Filosoficamente, você poderia chamar sessões e fotos de 'recursos', mas, realisticamente, eu não os trataria da mesma maneira. A sessão é sempre intrinsecamente restrita ao usuário atual (daí o nome Session) e, pelo menos no ASP.NET, não há como acessar as sessões de outro usuário. Mesmo o desenvolvedor do aplicativo não possui uma maneira direta de enumerar todas as sessões ativas ou meios de eliminar as sessões individualmente. Você pode reiniciar o aplicativo para eliminar todas as sessões (InProc), mas eu não chamaria esse controle de acesso. URLs à parte, a questão ainda permanece: GET ou POST?
Daniel Liuzzi
Recurso, portanto, seu endereço (URL) é parte importante do REST. Portanto, se você escolher o URL como eu disse, DELETE se tornará a palavra correta - não GET ou POST. Além disso, mesmo se você estiver se limitando ao ASP.NET, sempre poderá ter seu provedor de estado personalizado, que pode lhe permitir enumerar as sessões e interromper outras, se necessário. Para sessões in-proc prontas para o uso, algumas brincadeiras no global.asax devem fornecer a funcionalidade. É realmente uma questão de saber se essa funcionalidade seria necessária ou não. Para necessidades pouco frequentes, as pessoas tendem a reiniciar o site para expulsar as pessoas.
precisa saber é o seguinte
Isso faz mais sentido para mim. Dê à API da Web uma rota de sessão e chame DELETE nela. Seja ../session ou ../session/current. Thankx @VinayC
Simon Hooper
16

O logout não faz nada para o próprio aplicativo. Ele altera o estado do usuário em relação ao aplicativo. Nesse caso, parece que sua pergunta é mais baseada em como o comando deve ser iniciado pelo usuário para iniciar esta ação. Como essa não é uma "ação destrutiva", verifique se a sessão foi abandonada ou destruída, mas que nem seu aplicativo nem seus dados foram alterados, não é inviável permitir que ambos os métodos iniciem um procedimento de logoff. A postagem deve ser usada por qualquer ação iniciada pelo usuário (por exemplo - o usuário clica em "Logout"), enquanto o get pode ser reservado para logouts iniciados pelo aplicativo (por exemplo - uma exceção que detecta uma possível invasão do usuário forçosamente redireciona para a página de login com um logout GET )

Joel Etherton
fonte
Interessante; Eu nunca pensei nisso dessa maneira. +1.
Stragner
É possível que isso dependa do aplicativo (algum tipo de comportamento de "exclusão em cascata"), mas você está certo.
Andres Jaan Tack
@ JoelEtherton Obrigado Joel, eu estava lendo as respostas, imaginando quando chegaria à correta. :)
Kirill Fuchs
4
É confuso porque o logout muda de estado. POST é o verbo para mudar de estado. GET é para obter dados sem estado. É confuso porque esperamos que as solicitações POST tenham cargas úteis. Conforme observado abaixo, DELETE estaria mais correto em um objeto de sessão.
Michael Cole
1
@ MichaelCole: Eu concordo com essa representação da dificuldade entre o POST e o GET. Eu não concordaria com o uso do verbo DELETE. DELETE é para manipular um recurso e a sessão não é um recurso nesse sentido. Considere, se você puder EXCLUIR, também poderá COLOCÁ-lo.
Joel Etherton
16

Olá, do meu ponto de vista, ao fazer login, verifique o nome de usuário / senha e, se houver algum, crie o token de login.

Token CREAT => método POST

Quando você está desconectando, distribui o token, portanto, para mim, o método mais lógico deve ser um DELETE

Token DELETE => método DELETE

miorey
fonte
4
Ângulo interessante.
Drumbeg
1
Eu uso esse método em meus aplicativos Spring Boot REST.
Please_Dont_Bully_Me_SO_Lords
1
semanticamente correto. Concordo ...
DAG
1

O cenário de pré-cache é interessante. Mas suponho que, se muitos sites inc SO, não se preocupem com isso, talvez você também não deva.

Ou talvez o link possa ser implementado em javascript?

Edit: Pelo que entendi, tecnicamente um GET deve ser para solicitações somente leitura, que não alteram o estado do aplicativo. Um POST deve ser para solicitações de gravação / edição que mudam de estado. No entanto, outros problemas de aplicativos podem preferir GET sobre POST para algumas solicitações de alteração de estado, e eu não acho que haja algum problema com isso.

Richard H
fonte
Obrigado. O estado do banco de dados não seria alterado, mas o estado da sessão seria. O único problema que vejo é o que mencionei na pergunta, sobre os usuários serem expulsos. Não destrutivo, mas bastante irritante. Eu costumo seguir o mantra "se os grandes fazem isso, então deve estar tudo bem" também. Eu só queria saber que opinião os outros têm sobre isso.
Daniel Liuzzi
0

Bem, se você deixar seu aplicativo Web abandonar a sessão por meio de um script de logoff, geralmente não será necessário. Normalmente, há uma variável de sessão exclusiva para a sessão que você deseja abandonar.

Roubar
fonte
Você poderia elaborar o "script de logoff"? Eu não tenho certeza se você está se referindo a definir uma expiração do cookie (o que não elimina a necessidade de uma maneira de deixar os usuários manualmente o logout.)
Daniel Liuzzi
Um script de logout encerraria a sessão do usuário (na verdade: navegador) que está chamando. No ASP.net, a sessão é um objeto do lado do servidor que pode ser abandonado. O PHP tem um sistema semelhante. Como esse navegador chama o script que encerra a sessão, ele já sabe qual final, eliminando a necessidade de variáveis ​​POST ou GET.
Rob
1
Sim, eu te pego agora. Eu já tenho o script no lugar, especificamente FormsAuthentication.SignOut (), mas minha pergunta é sobre como chamar o script, como em GET ou POST.
Daniel Liuzzi
Oh você tem o URL em um formulário? Não importa se você não está passando nenhuma informação para ele. A pior coisa que poderia acontecer é alguém abrir o script manualmente, se desconectando. Eu nem faria dele um campo de formulário, se não necessário, um link para o script também funcionaria. Se você enviar informações para o script, eu provavelmente faria um POST, para não mostrar nenhuma informação ao usuário (a menos que ele veja a fonte da página) e, se atualizar, receberá um aviso do navegador (página expirada), o que pode ser desejável.
Rob
0

Recentemente, eu estava trabalhando em um projeto que uso GET para sair. Abaixo está o código no Nodejs Express e funciona perfeitamente bem

seu router.js

const express = require("express");
router.get("/signout", signout);

seu controller.js

exports.signout  = (req, res) => {
        res.clearCookie('t'); //clearing cookie, which is 
            //assign to the user during sign in.          
            res.json({message : 'Signout success'});   
        };
xSachinx
fonte
-2

Não vejo como fazer logoff (removendo as permissões de usuário) é uma ação destrutiva. Isso ocorre porque a ação "logout" deve estar disponível apenas para usuários que já estão conectados, caso contrário, seria obsoleta.

Uma sequência gerada aleatoriamente contida nos cookies do navegador está representando a sua sessão do usuário. Existem várias maneiras de destruí-lo de forma tão eficaz. O logout é apenas um serviço para o visitante.

jpluijmers
fonte
2
wgetno modo spider, com um cookie de sessão correto em um wiki privado, era algo que eu realmente tive que fazer uma vez. Obviamente, um dos primeiros URLs rastreados foi /logout.
Helgi
5
Tente acessar SuperLogout.com para ver como as solicitações GET destrutivas para as /logoutpáginas realmente são. Por exemplo, você precisará fazer login no Gmail novamente, entrar no bate-papo novamente, encontrar seu lugar nas conversas do Hangouts que rolou etc. - e isso é apenas para Google.com.
Dan Dascalescu 29/01