Autenticación RESTful

745

¿Qué significa la autenticación RESTful y cómo funciona? No puedo encontrar una buena descripción general en Google. Lo único que entiendo es que pasa la clave de sesión (remeberal) en la URL, pero esto podría ser terriblemente incorrecto.

Jim Keener
fuente
3
Cuando busco Google Restful Authentication, encuentro una docena de complementos RoR. Supongo que NO son lo que estás buscando. Si no es RoR, entonces, ¿qué idioma? ¿Qué servidor web?
S.Lott
2
No será terriblemente incorrecto si usa HTTPS. La solicitud HTTP completa junto con la URL estaría encriptada.
Bharat Khatri
44
@BharatKhatri: Sí, lo haría. Nunca pasaría información confidencial en la URL visible para el usuario. Es mucho más probable que esta información se filtre con fines prácticos. HTTPS no puede ayudar por fugas accidentales.
Jo So
2
@jcoffland: ¿Qué quieres decir con autenticación RESTful real? Estoy interesado porque acabo de implementar la tercera vía desde la respuesta aceptada, sin embargo, no estoy contento con ella (no me gusta el parámetro adicional en la URL).
BlueLettuce16
44
algunas personas usan jwt.io/introduction para resolver esto. Ahora investigo sobre esto para resolver mi caso: stackoverflow.com/questions/36974163/… >> Espero que esto funcione bien.
toha

Respuestas:

586

Cómo manejar la autenticación en una arquitectura RESTful Cliente-Servidor es un tema de debate.

Comúnmente, se puede lograr, en el mundo SOA sobre HTTP a través de:

  • Autenticación básica HTTP sobre HTTPS;
  • Cookies y gestión de sesiones;
  • Token en encabezados HTTP (por ejemplo, OAuth 2.0 + JWT);
  • Autenticación de consulta con parámetros de firma adicionales.

Tendrá que adaptar, o incluso mezclar mejor esas técnicas, para que coincida con la arquitectura de su software en el mejor de los casos.

Cada esquema de autenticación tiene sus propios PRO y CON, dependiendo del propósito de su política de seguridad y arquitectura de software.

Autenticación básica HTTP sobre HTTPS

Esta primera solución, basada en el protocolo estándar HTTPS, es utilizada por la mayoría de los servicios web.

GET /spec.html HTTP/1.1
Host: www.example.org
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

Es fácil de implementar, está disponible de forma predeterminada en todos los navegadores, pero tiene algunos inconvenientes conocidos, como la horrible ventana de autenticación que se muestra en el navegador, que persistirá (no hay una característica similar a LogOut aquí), algo de consumo de CPU adicional del lado del servidor, y el hecho de que el nombre de usuario y la contraseña se transmiten (a través de HTTPS) al Servidor (debería ser más seguro permitir que la contraseña permanezca solo en el lado del cliente, durante la entrada del teclado, y se almacene como hash seguro en el Servidor) .

Podemos usar la autenticación implícita , pero también requiere HTTPS, ya que es vulnerable a ataques MiM o Replay , y es específico de HTTP.

Sesión a través de cookies

Para ser honesto, una sesión administrada en el servidor no es realmente sin estado.

Una posibilidad podría ser mantener todos los datos dentro del contenido de las cookies. Y, por diseño, la cookie se maneja en el lado del servidor (el cliente, de hecho, ni siquiera intenta interpretar estos datos de la cookie: solo la devuelve al servidor en cada solicitud sucesiva). Pero estos datos de cookies son datos de estado de la aplicación, por lo que el cliente debe administrarlos, no el servidor, en un mundo sin estado puro.

GET /spec.html HTTP/1.1
Host: www.example.org
Cookie: theme=light; sessionToken=abc123

La técnica de cookies en sí está vinculada a HTTP, por lo que no es realmente RESTful, que debería ser independiente del protocolo, en mi humilde opinión. Es vulnerable a los ataques MiM o Replay .

Otorgado a través de token (OAuth2)

Una alternativa es colocar un token dentro de los encabezados HTTP para que la solicitud se autentique. Esto es lo que hace OAuth 2.0, por ejemplo. Vea el RFC 6749 :

 GET /resource/1 HTTP/1.1
 Host: example.com
 Authorization: Bearer mF_9.B5f-4.1JqM

En resumen, esto es muy similar a una cookie y sufre los mismos problemas: no es apátrida, depende de los detalles de transmisión de HTTP y está sujeto a muchas debilidades de seguridad , incluidos MiM y Replay, por lo que debe usarse solo sobre HTTPS. Por lo general, un JWT se usa como token.

Autenticación de consulta

La autenticación de consulta consiste en firmar cada solicitud RESTful a través de algunos parámetros adicionales en el URI. Ver este artículo de referencia .

Se definió como tal en este artículo:

Todas las consultas REST deben autenticarse firmando los parámetros de consulta ordenados en orden alfabético en minúsculas utilizando la credencial privada como token de firma. La firma debe ocurrir antes de que la URL codifique la cadena de consulta.

Esta técnica es quizás la más compatible con una arquitectura sin estado, y también se puede implementar con una administración de sesión ligera (usando sesiones en memoria en lugar de persistencia DB).

Por ejemplo, aquí hay una muestra genérica de URI del enlace de arriba:

GET /object?apiKey=Qwerty2010

debe transmitirse como tal:

GET /object?timestamp=1261496500&apiKey=Qwerty2010&signature=abcdef0123456789

La cadena que se firma es /object?apikey=Qwerty2010&timestamp=1261496500y la firma es el hash SHA256 de esa cadena usando el componente privado de la clave API.

El almacenamiento en caché de datos del lado del servidor puede estar siempre disponible. Por ejemplo, en nuestro marco, almacenamos en caché las respuestas a nivel de SQL, no a nivel de URI. Por lo tanto, agregar este parámetro adicional no rompe el mecanismo de caché.

Consulte este artículo para obtener algunos detalles sobre la autenticación RESTful en nuestro marco ORM / SOA / MVC cliente-servidor, basado en JSON y REST. Dado que permitimos la comunicación no solo a través de HTTP / 1.1, sino también canalizaciones con nombre o mensajes GDI (localmente), intentamos implementar un patrón de autenticación verdaderamente RESTful, y no confiar en la especificidad HTTP (como encabezado o cookies).

Nota posterior : agregar una firma en el URI puede verse como una mala práctica (ya que, por ejemplo, aparecerá en los registros del servidor http), por lo que debe mitigarse, por ejemplo, mediante un TTL adecuado para evitar repeticiones. Pero si sus registros http están comprometidos, seguramente tendrá mayores problemas de seguridad.

En la práctica, la próxima autenticación de tokens MAC para OAuth 2.0 puede ser una gran mejora con respecto al esquema actual "Concedido por token". Pero esto sigue siendo un trabajo en progreso y está vinculado a la transmisión HTTP.

Conclusión

Vale la pena concluir que REST no solo se basa en HTTP, incluso si, en la práctica, también se implementa principalmente a través de HTTP. REST puede usar otras capas de comunicación. Por lo tanto, una autenticación RESTful no es solo un sinónimo de autenticación HTTP, sea lo que sea que Google responda. Incluso no debe usar el mecanismo HTTP en absoluto, sino que debe abstraerse de la capa de comunicación. Y si usa la comunicación HTTP, gracias a la iniciativa Let's Encrypt no hay razón para no usar HTTPS adecuado, que se requiere además de cualquier esquema de autenticación.

Arnaud Bouchez
fuente
55
Si lo utiliza Cookiecomo un mejor reemplazo HTTP Basic Auth, puede realizar una autenticación verdaderamente sin estado con un método para expirar la autenticación y la capacidad de cerrar sesión. Una implementación de ejemplo podría usar una cookie llamada Emulated-HTTP-Basic-Authcon un valor similar a la autenticación básica HTTP real y además establecer el tiempo de caducidad. El cierre de sesión se puede implementar eliminando esa cookie. Supongo que cualquier cliente capaz de admitir HTTP Basic Auth también puede admitir la autenticación de cookies de esta manera.
Mikko Rantalainen
44
@MikkoRantalainen Pero esta cookie seguirá siendo administrada por el servidor, como escribí. Es una especie de apátrida, pero no apátrida "pura". En todos los casos, necesita un código JavaScript dedicado al inicio / cierre de sesión del cliente, que es perfectamente posible, por ejemplo, con HTTP Digest Auth : buena idea, pero no es un gran beneficio, aquí, reinventar la rueda.
Arnaud Bouchez
44
Yo diría que el servidor implementa la interfaz de usuario y la lógica para configurar el encabezado, pero el encabezado en sí no tiene estado. Un cliente diseñado para la API podría omitir el uso de la ayuda del servidor para configurar el encabezado y simplemente pasar la información requerida similar a la autenticación básica HTTP. Mi punto es que los UA (navegadores) comunes tienen una implementación tan pobre de la autenticación básica que no se puede usar. En su Cookielugar, se puede usar una emulación proporcionada por el servidor para las mismas cosas en otro encabezado ( ).
Mikko Rantalainen
66
Creo que la respuesta correcta es stackoverflow.com/questions/6068113/…
graffic
77
La solicitud de contraseña fea para la autorización HTTP solo aparecerá si el servidor lo solicita enviando la respuesta no autorizada 401. Si no te gusta, solo envía un 403 Prohibido. La página de error puede incluir un método para iniciar sesión o un enlace a ella. Sin embargo, el mayor argumento contra las cookies Y la autenticación http (independientemente de si el estado es del lado del servidor o del lado del cliente) es que son vulnerables a la falsificación de solicitudes entre sitios. Por este motivo, el mejor enfoque es un esquema de autorización personalizado, un encabezado de autorización personalizado o un parámetro GET o POST personalizado.
Dobes Vandermeer
418

Dudo si las personas que gritaban con entusiasmo "Autenticación HTTP" alguna vez intentaron hacer una aplicación basada en navegador (en lugar de un servicio web de máquina a máquina) con REST (sin intención de ofender, simplemente no creo que alguna vez hayan enfrentado las complicaciones) .

Los problemas que encontré al usar la autenticación HTTP en los servicios RESTful que producen páginas HTML para ver en un navegador son:

  • El usuario generalmente obtiene un cuadro de inicio de sesión feo hecho por el navegador, que es muy poco amigable para el usuario. no puede agregar recuperación de contraseña, cuadros de ayuda, etc.
  • cerrar la sesión o iniciar sesión con un nombre diferente es un problema: los navegadores seguirán enviando información de autenticación al sitio hasta que cierre la ventana
  • los tiempos de espera son difíciles

Aquí hay un artículo muy perspicaz que aborda estos puntos por punto , pero esto resulta en una gran cantidad de hackers de JavaScript específicos del navegador, soluciones alternativas para soluciones alternativas, etc. Como tal, tampoco es compatible con versiones anteriores, por lo que requerirá un mantenimiento constante a medida que se publiquen nuevos navegadores. No considero ese diseño limpio y claro, además siento que es mucho trabajo extra y dolor de cabeza solo para poder mostrar con entusiasmo mi insignia REST a mis amigos.

Creo que las cookies son la solución. Pero espera, las galletas son malvadas, ¿no? No, no lo son, la forma en que se usan las cookies es mala. Una cookie en sí misma es solo una parte de la información del lado del cliente, al igual que la información de autenticación HTTP que el navegador registraría mientras navega. Y esta información del lado del cliente se envía al servidor en cada solicitud, de nuevo al igual que la información de autenticación HTTP. Conceptualmente, la única diferencia es que el servidor puede determinar el contenido de esta parte del estado del lado del cliente como parte de su respuesta.

Al hacer que las sesiones sean un recurso RESTful con solo las siguientes reglas:

  • Una sesión asigna una clave a una identificación de usuario (y posiblemente una marca de tiempo de última acción para tiempos de espera)
  • Si existe una sesión , eso significa que la clave es válida.
  • Iniciar sesión significa PUBLICAR en / sesiones, una nueva clave se configura como una cookie
  • Cerrar sesión significa ELIMINAR / sessions / {key} (con la POST sobrecargada, recuerde, somos un navegador, y HTML 5 todavía es un largo camino por recorrer)
  • La autenticación se realiza enviando la clave como una cookie en cada solicitud y verificando si la sesión existe y es válida

La única diferencia con la autenticación HTTP, ahora, es que la clave de autenticación es generada por el servidor y enviada al cliente que la sigue enviando, en lugar de que el cliente la compute a partir de las credenciales ingresadas.

converter42 agrega que cuando se usa https (que deberíamos), es importante que la cookie tenga su bandera de seguridad establecida para que la información de autenticación nunca se envíe a través de una conexión no segura. Gran punto, no lo había visto yo mismo.

Creo que esta es una solución suficiente que funciona bien, pero debo admitir que no soy lo suficientemente experto en seguridad para identificar posibles agujeros en este esquema; todo lo que sé es que cientos de aplicaciones web que no son RESTful usan esencialmente lo mismo protocolo de inicio de sesión ($ _SESSION en PHP, HttpSession en Java EE, etc.). El contenido del encabezado de la cookie simplemente se usa para abordar un recurso del lado del servidor, al igual que se podría usar un lenguaje de aceptación para acceder a los recursos de traducción, etc. Siento que es lo mismo, pero tal vez otros no. ¿Qué piensan chicos?

skrebbel
fuente
68
Esta es una respuesta pragmática y la solución propuesta funciona. Sin embargo, usar los términos "RESTful" y "session" en la misma oración es simplemente incorrecto (a menos que también haya "not" en el medio;). En otras palabras: cualquier servicio web que usa sesiones NO ES RESTful (por definición). No me malinterpreten, todavía puede usar esta solución (YMMV), pero el término "RESTful" no se puede usar para ello. Recomiendo el libro de O'Reilly sobre REST, que es muy legible y explica el tema en profundidad.
johndodo
23
@skrebbel: la solución REST pura enviaría datos de autenticación cada vez que solicite un recurso, que no es perfecto (HTTP Auth hace esto). La solución propuesta funciona y es mejor para la mayoría de los casos de uso, pero no es RESTful. No hay necesidad de guerra, yo también uso esta solución. Simplemente no digo que sea RESTful. :)
johndodo
94
Oh, vamos, da un ejemplo entonces. ¿Qué es esa otra forma, que funciona bien? Realmente me gustaría saberlo. HTTP Auth seguramente no lo es, no puede cerrar sesión sin cerrar el navegador y no puede ofrecer una UX de inicio de sesión decente sin muchos JS específicos del navegador no compatibles con el futuro. No me importa mucho "puramente RESTful" versus "casi RESTful" y todo el debate religioso asociado, pero si dices que hay varias formas, deberías explicarlas.
skrebbel
15
Una autenticación verdaderamente RESTful con agentes de usuario del mundo real (también conocidos como "navegadores") consiste en una cookie que contiene el valor de Autenticación HTTP. De esta forma, el servidor puede proporcionar la interfaz de usuario para ingresar el nombre de usuario y la contraseña y puede forzar el cierre de sesión (eliminando la cookie). Además, en lugar de responder 401 para requerir el inicio de sesión cuando falla la autenticación, el servidor debe utilizar la redirección temporal a la pantalla de inicio de sesión y, después de iniciar sesión correctamente, utilizar la redirección temporal a la ubicación anterior. Además, el servidor debe incrustar la acción de cierre de sesión (formulario POST) en casi todas las páginas para los usuarios registrados.
Mikko Rantalainen
15
No veo nada malo con el uso de "descanso" y "sesión" en la misma oración, siempre que esté claro que la sesión existe solo en el lado del cliente. No estoy seguro de por qué se hace tanto alboroto por este concepto.
Joe Phillips el
140

Ya se ha dicho lo suficiente sobre este tema por buena gente aquí. Pero aquí están mis 2 centavos.

Hay 2 modos de interacción:

  1. humano a máquina (HTM)
  2. máquina a máquina (MTM)

La máquina es el denominador común, expresado como las API REST, y los actores / clientes son humanos o máquinas.

Ahora, en una arquitectura verdaderamente RESTful, el concepto de apatridia implica que todos los estados de aplicación relevantes (es decir, los estados del lado del cliente) deben suministrarse con todas y cada una de las solicitudes. Por relevante, se entiende que lo que sea requerido por la API REST para procesar la solicitud y servir una respuesta adecuada.

Cuando consideramos esto en el contexto de las aplicaciones de persona a máquina, "basadas en el navegador" como señala Skrebbel anteriormente, esto significa que la aplicación (web) que se ejecuta en el navegador deberá enviar su estado y la información relevante con cada solicitud hace a las API REST de back-end.

Considere esto: tiene una plataforma de datos / información expuesta como activo de las API REST. Quizás tenga una plataforma de BI de autoservicio que maneje todos los cubos de datos. Pero desea que sus clientes (humanos) accedan a esto a través de (1) aplicación web, (2) aplicación móvil y (3) alguna aplicación de terceros. Al final, incluso la cadena de MTM conduce a HTM, correcto. Por lo tanto, los usuarios humanos permanecen en la cúspide de la cadena de información.

En los primeros 2 casos, tiene un caso para la interacción de persona a máquina, siendo la información realmente consumida por un usuario humano. En el último caso, tiene un programa de máquina que consume las API REST.

El concepto de autenticación se aplica en todos los ámbitos. ¿Cómo diseñarás esto para que se acceda a tus API REST de manera uniforme y segura? A mi modo de ver esto, hay 2 formas:

Camino-1:

  1. No hay inicio de sesión, para empezar. Cada solicitud realiza el inicio de sesión
  2. El cliente envía sus parámetros de identificación + los parámetros específicos de la solicitud con cada solicitud
  3. La API REST los toma, da la vuelta, hace ping al almacén de usuarios (lo que sea que sea) y confirma la autenticación
  4. Si se establece la autenticación, atiende la solicitud; de lo contrario, niega con el código de estado HTTP apropiado
  5. Repita lo anterior para cada solicitud en todas las API REST de su catálogo

Camino-2:

  1. El cliente comienza con una solicitud de autenticación.
  2. Una API REST de inicio de sesión manejará todas esas solicitudes
  3. Toma los parámetros de autenticación (clave API, uid / pwd o lo que elija) y verifica la autenticación en el almacén de usuarios (LDAP, AD o MySQL DB, etc.)
  4. Si se verifica, crea un token de autenticación y se lo devuelve al cliente / llamante
  5. La persona que llama luego envía este token de autenticación + solicitud de parámetros específicos con cada solicitud posterior a otras API REST comerciales, hasta que cierre la sesión o hasta que expire el contrato de arrendamiento

Claramente, en Way-2, las API REST necesitarán una forma de reconocer y confiar en el token como válido. La API de inicio de sesión realizó la verificación de autenticación y, por lo tanto, otras API de REST de su catálogo deben confiar en esa "clave de valet".

Esto, por supuesto, significa que la clave / token de autenticación deberá almacenarse y compartirse entre las API REST. Este repositorio de tokens de confianza compartido puede ser local / federado, lo que permite que las API REST de otras organizaciones confíen entre sí.

Pero yo divago.

El punto es que se debe mantener y compartir un "estado" (sobre el estado autenticado del cliente) para que todas las API REST puedan crear un círculo de confianza. Si no hacemos esto, que es el Way-1, debemos aceptar que se debe realizar un acto de autenticación para cualquiera / todas las solicitudes que ingresen.

La autenticación es un proceso que requiere muchos recursos. Imagine ejecutar consultas SQL, para cada solicitud entrante, en su tienda de usuarios para verificar la coincidencia de uid / pwd. O, para cifrar y realizar coincidencias hash (el estilo AWS). Y arquitectónicamente, cada API REST necesitará realizar esto, sospecho, usando un servicio de inicio de sesión común. Porque, si no lo hace, entonces ensucia el código de autenticación en todas partes. Un gran desastre.

Entonces más capas, más latencia.

Ahora, tome Way-1 y aplique a HTM. ¿A su usuario (humano) realmente le importa si tiene que enviar uid / pwd / hash o lo que sea con cada solicitud? No, siempre y cuando no la molestes lanzando la página de autenticación / inicio de sesión cada segundo. Buena suerte teniendo clientes si lo haces. Entonces, lo que hará es almacenar la información de inicio de sesión en algún lugar del lado del cliente, en el navegador, justo al principio, y enviarla con cada solicitud realizada. Para el usuario (humano), ella ya inició sesión y hay una "sesión" disponible. Pero en realidad, ella se autentica en cada solicitud.

Lo mismo con Way-2. Su usuario (humano) nunca se dará cuenta. Entonces no se hizo daño.

¿Qué pasa si aplicamos Way-1 a MTM? En este caso, dado que es una máquina, podemos aburrir a este tipo pidiéndole que envíe información de autenticación con cada solicitud. ¡A nadie le importa! Realizar Way-2 en MTM no provocará ninguna reacción especial; Es una maldita máquina. ¡Podría importarle menos!

Entonces, realmente, la pregunta es qué se adapta a sus necesidades. La apatridia tiene un precio que pagar. Paga el precio y sigue adelante. Si quieres ser purista, paga el precio por eso también y sigue adelante.

Al final, las filosofías no importan. Lo que realmente importa es el descubrimiento de información, la presentación y la experiencia de consumo. Si la gente ama tus API, hiciste tu trabajo.

Kingz
fuente
3
Señor, usted ha explicado esto tan hermosamente que tengo una idea clara del tema / pregunta básica en cuestión. ¡Eres como el Buda! ¿Puedo agregar que mediante el uso de HTTPS en la capa de transporte, incluso podemos evitar los ataques de Man In the Middle, para que nadie secuestre mi clave de identificación (si se elige Way-1)
Vishnoo Rath
¿No es siempre una máquina que realiza la autenticación? Al ser humano no le importan las contraseñas, es una molestia desafortunada para los usuarios que racionalizan correctamente la seguridad. Para mí es un problema del desarrollador cómo quieren que la máquina haga su trabajo.
Todd Baur
99
Leo tu respuesta; en su solución, por cada solicitud web que se origine en el navegador mediante clics del usuario, deberá enviar el "token de autenticación" de vuelta a la API a la que llame el usuario. ¿Entonces que? La API realiza la verificación en el token. ¿Contra que? Contra algún tipo de "tienda de tokens" que mantiene si ese token es válido o no. ¿No estás de acuerdo en que esa "tienda de tokens" se convierte en el guardián del "estado"? Realmente, sin importar cómo lo veas, alguien en algún lugar tiene que saber algo sobre los "tokens" que se pasan en las actividades de los usuarios. Ahí es donde vive la información del estado.
Kingz
55
Y por servicio "sin estado", lo que realmente se entiende es que ese componente de servidor en particular (las API CRUD) no tiene ningún estado. No reconocen a un usuario de otro y completan la solicitud del usuario en su totalidad en una transacción. Eso es apatridia. Pero alguien en algún lugar debe estar sentado y juzgar si este usuario es válido o no. No hay otra forma de hacer esto; claves o contraseñas o lo que sea. Cualquier cosa transmitida por el lado del usuario debe ser autenticada y autorizada.
Kingz
1
Te estás perdiendo Way-3, el enfoque híbrido. El cliente inicia sesión como en Way-2pero, como en Way-1, las credenciales no se verifican en ningún estado del lado del servidor. En cualquier caso, se crea un token de autenticación y se devuelve al cliente como en Way-2. Posteriormente se verifica la autenticidad de este token utilizando criptografía asimétrica sin buscar ningún estado específico del cliente.
jcoffland
50

Aquí hay una solución de autenticación verdaderamente y completamente RESTful:

  1. Cree un par de claves pública / privada en el servidor de autenticación.
  2. Distribuya la clave pública a todos los servidores.
  3. Cuando un cliente se autentica:

    3.1. emitir un token que contenga lo siguiente:

    • Tiempo de expiración
    • nombre de usuario (opcional)
    • IP de usuarios (opcional)
    • hash de una contraseña (opcional)

    3.2. Cifre el token con la clave privada.

    3.3. Envíe el token cifrado al usuario.

  4. Cuando el usuario accede a cualquier API, también debe pasar su token de autenticación.

  5. Los servidores pueden verificar que el token sea válido descifrándolo con la clave pública del servidor de autenticación.

Esta es una autenticación sin estado / RESTful.

Tenga en cuenta que si se incluyera un hash de contraseña, el usuario también enviaría la contraseña no cifrada junto con el token de autenticación. El servidor podría verificar que la contraseña coincidía con la contraseña que se utilizó para crear el token de autenticación mediante la comparación de hashes. Sería necesaria una conexión segura usando algo como HTTPS. Javascript en el lado del cliente podría manejar obtener la contraseña del usuario y almacenarla del lado del cliente, ya sea en la memoria o en una cookie, posiblemente encriptada con la clave pública del servidor .

jcoffland
fuente
55
¿Qué sucede si alguien se apodera de ese token de autenticación e invoca API con él pretendiendo ser cliente?
Abidi
2
@Abidi, sí, eso es un problema. Podría requerir una contraseña. Se podría incluir un hash de la contraseña en el token de autenticación. Si alguien pudiera robar el token, sería vulnerable a los ataques de fuerza bruta fuera de línea. Si se eligiera una frase de contraseña fuerte, eso no sería un problema. Tenga en cuenta que si utiliza el robo de tokens https, el atacante deberá obtener primero acceso a la máquina del cliente.
jcoffland
1
Porque solo el servidor de autenticación conoce la clave privada. Otros servidores pueden autenticar al usuario con solo conocer la clave pública y el token del usuario.
jcoffland
1
El cifrado y descifrado asimétrico es un orden de magnitud más lento (más intensivo en cómputo) que el cifrado simétrico. Tener el servidor usando la clave pública para descifrar el token en cada llamada sería un enorme cuello de botella en el rendimiento.
Craig
3
@jcoffland, realmente promovió su respuesta aquí (repetidamente :-) Pero no puedo dejar de comentar sobre los problemas de rendimiento (intensidad de cálculo) del uso de cifrado asimétrico en cada llamada. Simplemente no puedo ver una solución que tenga esa capacidad de escalar. Busque HTTPS y el protocolo SPDY. Hace todo lo posible para mantener las conexiones abiertas (HTTP keep-alives, que es estado) y sirve múltiples recursos en lotes a través de la misma conexión (más estado), y por supuesto SSL solo usa cifrado asimétrico para intercambiar una clave de cifrado simétrica ( también estado).
Craig
37

Para ser honesto, he visto excelentes respuestas aquí, pero algo que me molesta un poco es cuando alguien llevará todo el concepto de Stateless a un extremo donde se vuelve dogmático. Me recuerda a esos viejos fanáticos de Smalltalk que solo querían abrazar OO puro y si algo no es un objeto, entonces lo estás haciendo mal. Dáme un respiro.

Se supone que el enfoque RESTful le facilitará la vida y reducirá los gastos generales y el costo de las sesiones, trate de seguirlo, ya que es una buena idea, pero en el momento en que sigue una disciplina (cualquier disciplina / directriz) hasta el extremo donde ya no proporciona el beneficio para el que estaba destinado, entonces lo estás haciendo mal. Algunos de los mejores lenguajes actuales tienen programación funcional y orientación a objetos.

Si la forma más fácil de resolver su problema es almacenar la clave de autenticación en una cookie y enviarla al encabezado HTTP, entonces hágalo, simplemente no la abuse. Recuerde que las sesiones son malas cuando se vuelven pesadas y grandes, si toda su sesión consiste en una cadena corta que contiene una clave, ¿cuál es el problema?

Estoy abierto a aceptar correcciones en los comentarios, pero simplemente no veo el punto (hasta ahora) en hacer nuestras vidas miserables para evitar simplemente mantener un gran diccionario de hashes en nuestro servidor.

arg20
fuente
2
La gente no está tratando de prohibir que uses sesiones. Eres libre de hacerlo. Pero si lo haces, no es REST.
André Caldas
66
@ AndréCaldas no es REST de la misma manera que tener funciones o tipos primitivos en un idioma no es opuesto. No digo que sea aconsejable tener sesiones. Solo estoy dando mi opinión con respecto a seguir un conjunto de prácticas en la medida en que ya no brinden beneficios a alguien. (Por cierto, observe que no me opuse a sus comentarios, sin embargo, no diría que no es REST, diría que no es REST puro ).
arg20
Entonces, ¿cómo lo llamamos si no es RESTful? Y, seguramente, si una solicitud incluye el ID de sesión, ¿eso es tan apátrida como una solicitud que incluye un ID de usuario? ¿Por qué los ID de usuario no tienen estado y los ID de sesión tienen estado?
mfhholmes
1
Las cookies son vulnerables a la falsificación de solicitudes entre sitios, por lo que facilitan las infracciones de seguridad. Es mejor usar algo que el navegador no envíe automáticamente, como un encabezado personalizado o un esquema de autorización personalizado.
Dobes Vandermeer
1
De hecho, tratar de ser apátrida no se trata de dogmatismo, sino de una concepción común de SOA en sí. Los servicios siempre deberían beneficiarse de estar desacoplados y sin estado: en la práctica, facilita la ampliación, la disponibilidad y el mantenimiento. Por supuesto, debería ser lo más posible, y eventualmente necesitaría algunos "servicios de orquestación" para administrar esos servicios sin estado en un enfoque pragmático con estado.
Arnaud Bouchez
32

En primer lugar, un servicio web RESTful es INALÁMBRICO (o, en otras palabras, SESSIONLESS) Por lo tanto, un servicio RESTful no tiene ni debe tener un concepto de sesión o cookies involucrados. La forma de autenticar o autorizar en el servicio RESTful es usar el encabezado de Autorización HTTP como se define en las especificaciones HTTP RFC 2616. Cada solicitud debe contener el encabezado de Autorización HTTP, y la solicitud debe enviarse a través de una conexión HTTP (SSL). Esta es la forma correcta de autenticar y verificar la autorización de solicitudes en un servicio web RESTful HTTP. He implementado un servicio web RESTful para la aplicación Cisco PRIME Performance Manager en Cisco Systems. Y como parte de ese servicio web, también he implementado autenticación / autorización.

Rubens
fuente
55
La autenticación HTTP todavía requiere que el servidor realice un seguimiento de los identificadores y contraseñas de los usuarios. Esto no es completamente apátrida.
jcoffland
21
No tiene estado en el sentido de que cada solicitud es válida por sí sola sin ningún requisito de solicitudes anteriores. La forma en que esto se implementa en el servidor es otra cuestión, si la autenticación es costosa, podría hacer un poco de almacenamiento en caché y volver a autenticarse en la memoria caché. Muy pocos servidores están completamente sin estado donde la salida es puramente una función de la entrada. Suele ser una consulta o una actualización de algún estado.
Erik Martino
3
No es verdad. En este caso, todas sus solicitudes requieren el estado de una transacción anterior, es decir, el registro del usuario. No veo por qué la gente sigue tratando de decir que un nombre de usuario y una contraseña almacenados en el servidor no son del lado del servidor. Mira mi respuesta.
jcoffland
1
@jcoffland Además, su solución depende en gran medida de la capacidad del servidor API para descifrar el token firmado. Creo que este enfoque no solo es demasiado específico, sino también un poco sofisticado para ser considerado como EL enfoque R. Fielding tenía en mente abordar el problema de la autenticación RESTful.
Michael Ekoka
2
@jcoffland, ¿comprende cuán profundamente es el cifrado asimétrico más intensivo en cómputo (y por lo tanto, intensivo en recursos y profundamente lento)? Estás hablando de un esquema que usaría cifrado asimétrico en cada solicitud. El aspecto más lento de HTTPS, sin excepción, es el apretón de manos inicial que implica la creación de claves públicas / privadas para cifrar asimétricamente un secreto compartido que posteriormente se utiliza para cifrar simétricamente toda la comunicación resultante.
Craig
22

Ciertamente no se trata de "claves de sesión", ya que generalmente se usa para referirse a la autenticación sin sesión que se realiza dentro de todas las restricciones de REST. Cada solicitud es autodescriptiva y contiene suficiente información para autorizar la solicitud por sí sola sin ningún estado de aplicación del lado del servidor.

La forma más fácil de abordar esto es comenzando con los mecanismos de autenticación integrados de HTTP en RFC 2617 .

Justin Sheehy
fuente
La autenticación HTTP requiere que el servidor almacene el nombre de usuario y la contraseña. Este es el estado del lado del servidor y, por lo tanto, no es estrictamente REST. Mira mi respuesta.
jcoffland
3
@jcoffland: Eso simplemente no es cierto, en ambas cuentas. La primera autenticación HTTP no requiere que el servidor almacene la contraseña. El hash de la contraseña se almacena en su lugar (se recomienda bcrypt con más de 8 rondas). En segundo lugar, el servidor no tiene ningún estado ya que el encabezado de autorización se envía con cada solicitud. Y si considera los hashes de contraseña almacenados como estado , no tienen más estado que las claves públicas almacenadas.
Boris B.
1
@ Boris B., sí, entiendo que la contraseña se almacena como un hash. La contraseña hash sigue siendo un estado específico del cliente. La diferencia con el almacenamiento de una clave pública, como se describe en mi solución, es que solo hay una clave pública, la clave pública del servidor de autenticación. Esto es muy diferente a almacenar un hash de contraseña por usuario. No importa cómo lo disfraces si el servidor almacena una contraseña para cada usuario, entonces está almacenando por estado de usuario y no es 100% REST.
jcoffland
77
No creo que almacenar una contraseña hash de los usuarios en el servidor deba considerarse un estado del lado del servidor. Los usuarios son recursos que contienen información como nombre, dirección o contraseña hash.
Codepunkt
15

El artículo 'muy perspicaz' mencionado por @skrebel ( http://www.berenddeboer.net/rest/authentication.html ) analiza un método de autenticación complicado pero realmente roto.

Puede intentar visitar la página (que se supone que es visible solo para el usuario autenticado) http://www.berenddeboer.net/rest/site/authenticated.html sin ninguna credencial de inicio de sesión.

(Lo siento, no puedo comentar la respuesta).

Yo diría que REST y autenticación simplemente no se mezclan. REST significa sin estado pero 'autenticado' es un estado. No puede tenerlos a ambos en la misma capa. Si eres un defensor RESTful y desapruebas los estados, entonces tienes que ir con HTTPS (es decir, dejar el problema de seguridad en otra capa).

Ji Han
fuente
Stripe.com diría lo contrario a su comentario sobre REST y la autenticación no se mezcla ..
Erik
Sin estado solo se refiere al servidor, no al cliente. El cliente puede recordar todo el estado de la sesión y enviar lo que sea relevante con cada solicitud.
Dobes Vandermeer
Finalmente, alguien habla con sentido, pero la autenticación sin estado es posible usando criptografía de clave pública. Mira mi respuesta.
jcoffland
1
El servidor no tiene estado "autenticado". Recibe información a través de hipermedia y tiene que trabajar con ella para devolver lo solicitado. Nada menos, nada más. Si el recurso está protegido y requiere autenticación y autorización, el hipermedia proporcionado debe incluir esa información. No sé de dónde viene la idea de que autenticar a un usuario antes de devolver un recurso significa que el servidor está rastreando el estado. Proporcionar un nombre de usuario y una contraseña puede considerarse simplemente como proporcionar más parámetros de filtrado.
Michael Ekoka
"Diría que REST y autenticación simplemente no se mezclan". Suena como algo de sentido común. Excepto que un sistema que es incompatible con la autenticación ("autenticado" en sí mismo es, por supuesto, un estado) es de utilidad limitada. Siento que todos estamos discutiendo en la intersección de la practicidad y el dogmatismo purista, y francamente la practicidad debería ganar. Hay muchos aspectos de REST que son altamente beneficiosos sin entrar en contorsiones tratando de evitar el estado con respecto a la autenticación, ¿no es así?
Craig
12

Creo que la autenticación tranquila implica el paso de un token de autenticación como parámetro en la solicitud. Ejemplos son el uso de apikeys por api's. No creo que el uso de cookies o autenticación HTTP califique.

Bjorn
fuente
Deben evitarse las cookies y la autenticación HTTP debido a la vulnerabilidad CSRF.
Dobes Vandermeer
@DobesVandermeer ¿Puedes ver mi pregunta si puedes ayudar? stackoverflow.com/questions/60111743/…
Hemant Metalia
12

Actualización el 16-feb-2019

El enfoque mencionado anteriormente a continuación es esencialmente el tipo de concesión "Credencial de contraseña del propietario del recurso" de OAuth2.0 . Esta es una manera fácil de comenzar a funcionar. Sin embargo, con este enfoque, todas las aplicaciones de la organización terminarán con sus propios mecanismos de autenticación y autorización. El enfoque recomendado es el tipo de concesión "Código de autorización". Además, en mi respuesta anterior a continuación, recomendé el localStorage del navegador para almacenar tokens de autenticación. Sin embargo, he llegado a creer que la cookie es la opción correcta para este propósito. He detallado mis razones, el enfoque de implementación del tipo de concesión del código de autorización, las consideraciones de seguridad, etc. en esta respuesta de StackOverflow .


Creo que el siguiente enfoque se puede utilizar para la autenticación del servicio REST:

  1. Cree una API RESTful de inicio de sesión para aceptar el nombre de usuario y la contraseña para la autenticación. Utilice el método HTTP POST para evitar el almacenamiento en caché y SSL para la seguridad durante el tránsito En la autenticación exitosa, la API devuelve dos JWT: un token de acceso (validez más corta, por ejemplo, 30 minutos) y un token de actualización (validez más larga, por ejemplo, 24 horas)
  2. El cliente (una IU basada en web) almacena los JWT en el almacenamiento local y en cada llamada API posterior pasa el token de acceso en el encabezado "Autorización: token de portador # token de acceso"
  3. La API verifica la validez del token verificando la firma y la fecha de vencimiento. Si el token es válido, verifique si el usuario (interpreta el reclamo "sub" en JWT como nombre de usuario) tiene acceso a la API con una búsqueda de caché. Si el usuario está autorizado para acceder a la API, ejecute la lógica empresarial
  4. Si el token ha caducado, la API devuelve el código de respuesta HTTP 400
  5. El cliente, al recibir 400/401, invoca otra API REST con el token de actualización en el encabezado "Autorización: portador # token de actualización" para obtener un nuevo token de acceso.
  6. Al recibir la llamada con token de actualización, verifique si el token de actualización es válido verificando la firma y la fecha de vencimiento. Si el token de actualización es válido, actualice el caché derecho de acceso del usuario desde la base de datos y devuelva el nuevo token de acceso y el token de actualización. Si el token de actualización no es válido, devuelva el código de respuesta HTTP 400
  7. Si se devuelven un nuevo token de acceso y un token de actualización, vaya al paso 2. Si se devuelve el código de respuesta HTTP 400, el cliente asume que el token de actualización ha caducado y solicita el nombre de usuario y la contraseña al usuario
  8. Para cerrar sesión, purgue el almacenamiento local

Con este enfoque, estamos haciendo la operación costosa de cargar el caché con detalles de derechos de acceso específicos del usuario cada 30 minutos. Por lo tanto, si se revoca un acceso o se otorga un nuevo acceso, se tarda 30 minutos en reflejarse o se cierra la sesión seguido de un inicio de sesión.

Saptarshi Basu
fuente
entonces, ¿usarías esto para una API con un sitio web estático hecho con angular, por ejemplo? ¿Y las aplicaciones móviles?
Yazan Rawashdeh
8

Esa es la forma de hacerlo: usando OAuth 2.0 para iniciar sesión .

Puede usar otros métodos de autenticación distintos de Google siempre que sea compatible con OAuth.

moshe beeri
fuente
1
OAuth2 no es seguro sin HTTPS, ni apátrida.
Arnaud Bouchez
44
Nada es seguro sin HTTPS.
Craig
1
@Craig y HTTPS pueden no ser seguros tampoco, si la cadena de certificados se rompe, lo que puede ser por un bien mayor - en.wikipedia.org/wiki/Bullrun_(decryption_program) ;)
Arnaud Bouchez
1
@ArnaudBouchez ¿Por favor aclare cómo tener una cadena de certificados rota es para el bien mayor? No entiendo a dónde vas con eso. ;)
Craig
@ Craig Por favor, siga el enlace, y disfruta! Este enfoque de "bien mayor" fue claramente cínico en mi comentario: los sistemas tipo Bullrun están destinados a "nuestro propio bien" por nuestros amados y confiables gobiernos.
Arnaud Bouchez
3

El uso de una infraestructura de clave pública en la que el registro de una clave implica un enlace adecuado garantiza que la clave pública esté vinculada al individuo al que está asignada de una manera que garantice el no repudio

Ver http://en.wikipedia.org/wiki/Public_key_infrastructure . Si sigue los estándares adecuados de PKI, la persona o agente que usa la clave robada de manera incorrecta puede ser identificada y bloqueada. Si se requiere que el agente use un certificado, el enlace se vuelve bastante ajustado. Un ladrón inteligente y veloz puede escapar, pero deja más migajas.

DonB.
fuente
2

Para responder a esta pregunta desde mi entendimiento ...

Un sistema de autenticación que utiliza REST para que no necesite realmente rastrear o administrar a los usuarios en su sistema. Esto se hace utilizando los métodos HTTP POST, GET, PUT, DELETE. Tomamos estos 4 métodos y pensamos en ellos en términos de interacción de la base de datos como CREAR, LEER, ACTUALIZAR, ELIMINAR (pero en la web usamos POST y GET porque eso es lo que soportan las etiquetas de anclaje actualmente). Entonces, al tratar POST y GET como CREAR / LEER / ACTUALIZAR / BORRAR (CRUD), podemos diseñar rutas en nuestra aplicación web que podrán deducir qué acción de CRUD estamos logrando.

Por ejemplo, en una aplicación de Ruby on Rails podemos construir nuestra aplicación web de manera que si un usuario que ha iniciado sesión visita http://store.com/account/logout , el GET de esa página puede verse como el usuario que intenta cerrar sesión . En nuestro controlador de rieles, construiríamos una acción que desconecte al usuario y lo envíe de regreso a la página de inicio.

Un GET en la página de inicio de sesión generaría un formulario. una POST en la página de inicio de sesión se vería como un intento de inicio de sesión y tomaría los datos de POST y los usaría para iniciar sesión.

Para mí, es una práctica de usar métodos HTTP asignados a su significado de base de datos y luego construir un sistema de autenticación teniendo en cuenta que no necesita pasar ninguna identificación de sesión o rastrear sesiones.

Todavía estoy aprendiendo: si encuentras algo que he dicho que está mal, corrígeme, y si obtienes más información, publícalo aquí. Gracias.


fuente
2

Consejos válidos para asegurar cualquier aplicación web

Si desea proteger su aplicación, entonces definitivamente debe comenzar usando HTTPS en lugar de HTTP , esto asegura la creación de un canal seguro entre usted y los usuarios que evitará rastrear los datos enviados de un lado a otro a los usuarios y ayudará a mantener los datos Intercambio confidencial.

Puede usar JWT (JSON Web Tokens) para proteger las API RESTful , esto tiene muchos beneficios en comparación con las sesiones del lado del servidor, los beneficios son principalmente:

1- Más escalable, ya que sus servidores API no tendrán que mantener sesiones para cada usuario (lo que puede ser una gran carga cuando tiene muchas sesiones)

2- Los JWT son independientes y tienen los reclamos que definen el rol del usuario, por ejemplo, y a qué puede acceder y emitido en la fecha y fecha de vencimiento (después de lo cual JWT no será válido)

3- Más fácil de manejar a través de equilibradores de carga y si tiene múltiples servidores API ya que no tendrá que compartir datos de sesión ni configurar el servidor para enrutar la sesión al mismo servidor, siempre que una solicitud con un JWT llegue a cualquier servidor, se puede autenticar y autorizado

4- Menos presión en su base de datos y no tendrá que almacenar y recuperar constantemente la identificación y los datos de la sesión para cada solicitud

5- Los JWT no pueden ser manipulados si usa una clave segura para firmar el JWT, por lo que puede confiar en los reclamos en el JWT que se envía con la solicitud sin tener que verificar la sesión del usuario y si está autorizado o no , solo puede verificar el JWT y luego estará listo para saber quién y qué puede hacer este usuario.

Muchas bibliotecas proporcionan formas fáciles de crear y validar JWT en la mayoría de los lenguajes de programación, por ejemplo: en node.js uno de los más populares es jsonwebtoken

Dado que las API REST generalmente tienen como objetivo mantener el servidor sin estado, los JWT son más compatibles con ese concepto ya que cada solicitud se envía con token de autorización que es autónomo (JWT) sin que el servidor tenga que realizar un seguimiento de la sesión del usuario en comparación con las sesiones que hacen que el servidor servidor con estado para que recuerde al usuario y su función, sin embargo, las sesiones también se usan ampliamente y tienen sus ventajas, que puede buscar si lo desea.

Una cosa importante a tener en cuenta es que debe entregar de forma segura el JWT al cliente utilizando HTTPS y guardarlo en un lugar seguro (por ejemplo, en el almacenamiento local).

Puede obtener más información sobre los JWT en este enlace

Ahmed Elkoussy
fuente