Cerrar sesión: ¿OBTENER o POSTAR?

435

Esta pregunta no se trata de cuándo usar GET o POST en general; se trata de cuál es el recomendado para manejar el cierre de sesión de una aplicación web. He encontrado mucha información sobre las diferencias entre GET y POST en el sentido general, pero no encontré una respuesta definitiva para este escenario en particular.

Como pragmático, me inclino a usar GET, porque implementarlo es mucho más simple que POST; solo suelta un enlace simple y listo. Este parece ser el caso con la gran mayoría de los sitios web en los que puedo pensar, al menos desde lo alto de mi cabeza. Incluso Stack Overflow maneja el cierre de sesión con GET.

Lo que me hace dudar es el argumento (aunque antiguo) de que algunos aceleradores web / proxies pre-cachean páginas yendo y recuperando cada enlace que encuentran en la página, por lo que el usuario obtiene una respuesta más rápida cuando hace clic en ellos. No estoy seguro de si esto aún se aplica, pero si este fuera el caso, entonces, en teoría, un usuario con uno de estos aceleradores sería expulsado de la aplicación tan pronto como inicie sesión, porque su acelerador encontraría y recuperaría el cierre de sesión enlace incluso si ella nunca hizo clic en él.

Todo lo que he leído hasta ahora sugiere que POST debe usarse para "acciones destructivas", mientras que las acciones que no alteran el estado interno de la aplicación, como las consultas y demás, deben manejarse con GET . En base a esto, la verdadera pregunta aquí es:

¿El cierre de sesión de una aplicación se considera una acción destructiva / altera el estado interno de la aplicación?

Daniel Liuzzi
fuente
Bueno, suponiendo que visite el sitio por primera vez y que el enlace de cierre de sesión no esté presente, se cerrará la sesión cuando inicie sesión. Estaría bien después de iniciar sesión por segunda vez, ya que la URL de cierre de sesión ya está en caché. Pero se puede suponer que cualquier acelerador decente podría filtrar la mayoría de las URL de cierre de sesión.
HyperCas
2
HyperCas, los aceleradores que filtraban las URL de cierre de sesión era una teoría que estaba considerando y una de las razones por las que decidí publicar la pregunta. Me siento un poco reacio a confiar en la lógica del acelerador, y un día tengo un usuario con un acelerador horrible quejándose de que no puede iniciar sesión. ¿Sabes si siguen un estándar o si ese estándar existe?
Daniel Liuzzi
Cualquier acelerador que envíe automáticamente un formulario (por ejemplo) sería malware IMO ... es totalmente ilógico pensar que un acelerador envíe un formulario automáticamente. Imagina que visitas Google. ¿Cómo podría enviar el formulario de búsqueda? Nadie puede dar cuenta de Malware ya que es demasiado impredecible y no sigue las reglas.
Alex
3
@AlexW - Creo que entendiste mal mi pregunta. El escenario del acelerador que propuse es mostrar un posible problema al usar GET, no POST, por lo que no habría forma de publicar, solo enlaces simples que los aceleradores no tendrían problemas para seguir.
Daniel Liuzzi
1
Me doy cuenta de que llego años tarde para esto, pero Alex, eso no es lo que Daniel está preguntando. Está diciendo que si un usuario hace clic en un enlace de cierre de sesión y un acelerador devuelve la página de cierre de sesión en caché sin que llegue a la aplicación, entonces el usuario permanecerá conectado. cualquier cosa de todos modos.
Rob Grant

Respuestas:

476

Uso POST.

En 2010, el uso GETfue probablemente una respuesta aceptable. Pero hoy (en 2013), los navegadores buscarán previamente las páginas que "piensan" que visitará a continuación.

Este es uno de los desarrolladores de StackOverflow que habla sobre este problema en Twitter:

Me gustaría agradecer a mi banco por cerrar sesión en una solicitud GET, y al equipo de Chrome por la práctica búsqueda previa de URL.- Nick Craver ( @Nick_Craver ) 29 de enero de 2013

Dato curioso: StackOverflow solía manejar el cierre de sesión a través de GET, pero ya no.

David Murdoch
fuente
2
Gracias por esta actualización, Dave. Ni siquiera me di cuenta de que SO cambió su cierre de sesión a POST, y honestamente no tenía idea de que Chrome viene con la recuperación previa incorporada. Finalmente, el imbécil que usted citó nunca podría haber ofrecido un mejor ejemplo del problema que describí en mi mi pregunta y confirma mis sospechas. Estoy votando su respuesta y convirtiéndola en la respuesta aceptada.
Daniel Liuzzi
44
En mi navegador, el cierre de sesión de Stackoverflow se parece a <li> <a href="https://stackoverflow.com/users/logout"> cerrar sesión </a> </li> que es un OBTENER, no un POST
barcocoder
99
@ Mark0978, haga clic en el enlace.
David Murdoch
2
Interesante. Esa es probablemente una de mis características menos favoritas, un cierre de sesión que luego me pregunta si estoy seguro. Supongo que evita que la captación previa cierre la sesión, pero Amazon, Ebay y Gmail usan GET para cerrar sesión sin esa página de trucos entre lo que se le dice al usuario que es cerrar sesión y el evento de cierre de sesión real. Me imagino que entre páginas llevaría a muchas personas a creer erróneamente que se desconectaron. Los problemas con eso en SO son mínimos, no hay dinero involucrado, y el 99% de todo es público de todos modos.
Boatcoder
77
@Red De acuerdo con el estándar HTTP / 1.1, esto es culpa del servidor, no del navegador. Se espera que GET no tenga efectos secundarios en el lado del servidor. La norma incluso dice que "el usuario no solicitó los efectos secundarios, por lo que no se le puede hacer responsable de ellos".
eyuelt
45

En REST no debería haber sesión, por lo tanto, no hay nada que destruir. Un cliente REST se autentica en cada solicitud. Conectado o desconectado, es solo una ilusión.

Lo que realmente está preguntando es si el navegador continúa enviando la información de autenticación en cada solicitud.

Podría decirse que si su aplicación crea la ilusión de estar conectado, entonces debería poder "cerrar sesión" usando javascript. No se requiere viaje de ida y vuelta.


Disertación de Fielding - Sección 5.1.3

cada solicitud del cliente al servidor debe contener toda la información necesaria para comprender la solicitud y no puede aprovechar ningún contexto almacenado en el servidor. Por lo tanto, el estado de la sesión se mantiene completamente en el cliente

Darrel Miller
fuente
1
En realidad no estaba al tanto de esto. Entonces supongo que mi aplicación no será muy RESTful en absoluto, ya que estoy usando ASP.NET MVC con FormsAuthentication y se basa en sesiones ...
Daniel Liuzzi
19
pero en la práctica, la información de inicio de sesión se guarda en una cookie marcada con el httponlyatributo para evitar algunos riesgos xss, lo que significa que solo se puede restablecer desde el servidor (
salvo
66
'Manual' como en el usuario va a la configuración del navegador y elige la opción 'Borrar cookies'. Difícilmente es una forma aceptable de 'cerrar sesión' en un sitio web.
Remus Rusanu
1
@Remus Ahhh, cómo el ilustre navegador web hace que escribir aplicaciones web sea tan doloroso.
Darrel Miller el
1
@DarrelMiller sí, sin embargo, no revocar un JWT en el lado del servidor es una vulnerabilidad de seguridad. Incluso si los tokens no se almacenan en el servidor, deben incluirse en una lista negra cuando un usuario cierra sesión / cambia contraseñas / cambia roles / abandona / etc. para evitar abusos (al menos hasta que caduquen).
java-addict301
39

Una forma de GETabusar aquí es que una persona (competidor quizás :) colocó una etiqueta de imagen en src="<your logout link>"CUALQUIER LUGAR en Internet, y si un usuario de su sitio tropieza con esa página, se cerrará la sesión sin saberlo.

raveren
fuente
44
No, esto no está bien. Un enlace de cierre de sesión solo funcionará si se envían los datos de cookies correctos, que no serán de otro dominio. E incluso si la identificación de la sesión se almacena en la URL, tampoco funcionaría, ya que cambian para cada sesión.
Richard H
44
¡Guau, nunca pensé en eso! Entonces, hay otra razón para no usar GET, y otra razón por la que no entiendo por qué todos lo hacen. Maldita sea, ahora tengo la intención de incluir una "imagen" stackoverflow.com/users/logout también mi publicación y ver qué pasa :-D
Daniel Liuzzi
24
src = es una simple solicitud del navegador, no proviene del lado del servidor, sino del cliente. Lleva todas las cookies y proviene de la IP del usuario. Es por eso que funcionan los píxeles de seguimiento de anuncios. La única forma de determinar dicho exploit sería verificar el referente.
raveren
12
SuperLogout.com hace exactamente eso (cargar /logoutURL en imágenes ocultas), y funciona.
Dan Dascalescu
99
re: SuperLogout ... No sé por qué hice clic en eso.
MI Wright
21

Para ser correcto, GET / POST (u otros verbos) son acciones en algún recurso (dirigido por URL), por lo que generalmente se trata del estado del recurso y no del estado de la aplicación como tal. Entonces, en verdaderos espíritus, debe tener una URL como [host name]\[user name]\session, entonces 'BORRAR' sería el verbo correcto para cerrar la sesión.

Utilizando [host name]\bla bla\logoutcomo URL no realmente una forma REST completa (IMO), entonces ¿por qué debatir sobre el uso correcto de GET / POST en él?

Por supuesto, también uso GET para cerrar sesión en mis aplicaciones :-)

VinayC
fuente
2
En ese caso, argumentaría que tener la parte [nombre de usuario] en la URL parece innecesario, ya que los usuarios siempre cierran sesión (es decir, ELIMINAR) su propia sesión; nunca otros usuarios ':-)
Daniel Liuzzi
1
En realidad no, estamos diciendo que la sesión es un recurso y queremos eliminarla. Entonces, para abordar cualquier sesión de manera uniforme, debe tener un nombre de usuario como parte de la URL. Su argumento es tan bueno como decir que emitir una acción PUT en [galería de fotos] \ fotos significa que está agregando a sus fotos (disponible en [galería de fotos] \ [nombre de usuario] \ fotos). Los diferentes recursos deben abordarse explícitamente, no puede haber ninguna implícita en ello. El sitio puede permitir que otros usuarios agreguen imágenes a su galería; sería parte del control de acceso al igual que puede tener un súper usuario que puede matar las sesiones de cualquiera.
VinayC
1
Filosóficamente hablando, podrías llamar a las sesiones y fotos 'recursos', pero de manera realista no las trataría igual. Las sesiones siempre están intrínsecamente restringidas al usuario actual (de ahí el nombre de sesión) y, al menos en ASP.NET, no hay forma de acceder a las sesiones de otro usuario. Incluso el desarrollador de la aplicación no tiene una forma directa de enumerar todas las sesiones activas, o medios para matar sesiones individualmente. Podría reiniciar la aplicación para eliminar todas las sesiones (InProc), pero no llamaría a ese control de acceso. Dejando a un lado las URL, la pregunta sigue siendo: ¿OBTENER o PUBLICAR?
Daniel Liuzzi
Recurso, por lo tanto, su dirección (URL) es una parte importante de REST. Entonces, si elige la URL como dije, DELETE se convierte en la palabra correcta, no GET o POST. Además, incluso si se limita a ASP.NET, siempre puede tener su proveedor de estado personalizado que le permita enumerar las sesiones y eliminar otras sesiones si es necesario. Para sesiones in-proc listas para usar, algunos retoques en global.asax deberían brindarle la funcionalidad. Es realmente una cuestión de si tal funcionalidad sería necesaria o no. Para necesidades poco frecuentes, la gente tiende a reiniciar el sitio web para echar a la gente del sitio.
VinayC
Esto tiene más sentido para mí. Dele a la API web una ruta de sesión y llame a DELETE en ella. Sea eso ../session o ../session/current. Thankx @VinayC
Simon Hooper
16

Cerrar sesión no hace nada a la aplicación en sí. Cambia el estado del usuario en relación con la aplicación. En este caso, parece que su pregunta se basa más en cómo debe iniciarse el comando desde el usuario para comenzar esta acción. Dado que esta no es una "acción destructiva", asegúrese de que la sesión se abandone o destruya pero que no se alteren su aplicación o sus datos, no es inviable permitir que ambos métodos inicien un procedimiento de cierre de sesión. La publicación debe ser utilizada por cualquier acción iniciada por el usuario (p. Ej., El usuario hace clic en "Cerrar sesión"), mientras que get se puede reservar para los cierres de sesión iniciados por la aplicación (p. Ej., Una excepción que detecta la posible intrusión del usuario redirige a la página de inicio de sesión con un cierre de sesión GET )

Joel Etherton
fuente
Interesante; Nunca lo pensé de esta manera. +1.
extraño
Esto podría depender de la aplicación (algún tipo de comportamiento de "eliminación en cascada"), pero tiene razón.
Andres Jaan Tack
@JoelEtherton Gracias Joel, estaba leyendo las respuestas preguntándome cuándo llegaría a la correcta. :)
Kirill Fuchs
44
Es confuso porque el cierre de sesión cambia de estado. POST es el verbo para cambiar de estado. GET es para obtener datos sin estado. Es confuso porque esperamos que las solicitudes POST tengan cargas útiles. Como se indica a continuación, DELETE sería más correcto en un objeto de sesión.
Michael Cole
1
@ MichaelCole: Estoy de acuerdo con esa representación de la dificultad entre POST y GET. Sin embargo, no estaría de acuerdo con el uso del verbo DELETE. DELETE es para manejar un recurso, y la sesión no es un recurso en este sentido. Tenga en cuenta que si puede BORRARLO, también debería poder PONERLO.
Joel Etherton el
16

Hola, desde mi punto de vista, cuando inicias sesión, verificas nombre de usuario / contraseña y, si coinciden, creas el token de inicio de sesión.

CREAR token => método POST

Cuando estás cerrando la sesión, destruyes el token, por lo que para mí el método más lógico debería ser ELIMINAR

DELETE token => método DELETE

miorey
fuente
44
Ángulo interesante
Drumbeg
1
Yo uso ese método en mis aplicaciones Spring Boot REST.
Please_Dont_Bully_Me_SO_Lords
1
semánticamente correcto. Estoy de acuerdo ...
DAG
1

El escenario de pre-almacenamiento en caché es interesante. Pero supongo que si muchos sitios inc SO no se preocupan por esto, entonces quizás tampoco debería hacerlo.

¿O tal vez el enlace podría implementarse en JavaScript?

Editar: Según tengo entendido, técnicamente un GET debe ser para solicitudes de solo lectura, que no cambian el estado de la aplicación. Una POST debe ser para solicitudes de escritura / edición que cambian de estado. Sin embargo, otros problemas de la aplicación pueden preferir GET sobre POST para algunas solicitudes que cambian de estado, y no creo que haya ningún problema con esto.

Richard H
fuente
Gracias. El estado de la base de datos no se cambiaría, pero el estado de la sesión sí. El único problema que veo es el que mencioné en la pregunta, sobre los usuarios expulsados. No destructivo pero bastante molesto. Por lo general, sigo el mantra "si los grandes lo hacen, entonces debe estar bien". Solo quería saber qué opinión tienen otros sobre esto.
Daniel Liuzzi
0

Bueno, si deja que su aplicación web abandone la sesión a través de un script de cierre de sesión, por lo general, tampoco necesita. Normalmente hay una variable de sesión que es única para la sesión que desea abandonar.

Robar
fuente
¿Podría elaborar el "script de cierre de sesión"? No estoy seguro de si se refiere a establecer una caducidad de cookies (lo que no elimina la necesidad de permitir que los usuarios cierren sesión manualmente)
Daniel Liuzzi
Un script de cierre de sesión finalizará la sesión del usuario (en realidad: navegador) que lo llama. En ASP.net, la sesión es un objeto del lado del servidor que se puede abandonar. PHP tiene un sistema similar. Debido a que ese navegador llama al script que finaliza la sesión, ya sabe cuál finalizar, eliminando la necesidad de variables POST o GET.
Rob
1
Sí, te entiendo ahora. Ya tengo el script en su lugar, específicamente FormsAuthentication.SignOut (), pero mi pregunta es sobre cómo invocar el script, como en GET o POST.
Daniel Liuzzi
Oh tienes la url en un formulario? No importa si no le está pasando ninguna información. Lo peor que podría pasar es que alguien abra manualmente el script y cierre sesión. Ni siquiera lo convertiría en un campo de formulario si no fuera necesario, un enlace al script también funcionaría. Si envía información a la secuencia de comandos, probablemente iría a una POST, para no mostrar ninguna información al usuario (a menos que vea la fuente de la página), y si se actualizan recibirán una advertencia de su navegador (página expirada), lo que podría ser deseable.
Rob
0

Recientemente estaba trabajando en un proyecto que uso GET para cerrar sesión A continuación se muestra el código en Nodejs Express y funciona perfectamente bien

su router.js

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

su controlador.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
fuente
-2

No veo cómo desconectarse (reducir los permisos de usuario) es una acción destructiva. Esto se debe a que la acción "cerrar sesión" solo debe estar disponible para los usuarios que ya han iniciado sesión; de lo contrario, sería obsoleta.

Una cadena generada al azar contenida en las cookies de su navegador representa a su sesión de usuario. Hay muchas formas de destruirlo, por lo que cerrar la sesión de manera efectiva es simplemente un servicio para su visitante.

jpluijmers
fuente
2
wgeten modo araña con una cookie de sesión correcta en un wiki privado fue algo que tuve que hacer una vez. Por supuesto, una de las primeras URL rastreadas fue /logout.
Helgi
55
Intente ir a SuperLogout.com para ver cuán destructivas /logoutson realmente las solicitudes GET a las páginas. Por ejemplo, tendrá que iniciar sesión en Gmail nuevamente, iniciar sesión en el chat nuevamente, encontrar su lugar en cualquier conversación de Hangouts que haya desplazado, etc., y esto es solo para Google.com.
Dan Dascalescu