web services - auth - Autenticación para servicios web REST
que es api auth (7)
Estoy empezando a diseñar un servicio web REST, y no tengo claro cuál es el mejor enfoque para la autenticación. El servicio permitirá a los usuarios individuales acceder / administrar sus propios datos, por lo que se requiere algún tipo de autenticación de usuario. He estado mirando estas opciones:
- OAuth
OAuth parece ser más acerca de la autorización en lugar de la autenticación. Planeo manejar la autorización de forma nativa dentro de los servicios, por lo que no estoy buscando una solución para esto. Pero, ¿OAuth también es apropiado para la autenticación?
- OpenID
OpenID ciertamente proporciona una solución para la autenticación, pero esto está más orientado a permitir que los usuarios usen sus credenciales de terceros (Google, Yahoo, etc.). Aunque me gustaría apoyar esto, esta no es una preocupación principal para mí, y lo haré. Definitivamente, permita que los usuarios se registren con credenciales nativas (correo electrónico / contraseña).
- Autenticación HTTP básica
Esto es simple de implementar, pero entiendo que este puede no ser un método muy seguro. Además, parecería requerir el intercambio de credenciales para cada acceso, pero preferiría que el usuario se autenticara una vez y luego continuara accediendo a través de un token de sesión.
- Autenticación personalizada
Básicamente, transfiero mi propio servicio de inicio de sesión / generación de tokens, y requiero un token válido para acceder a todos los otros recursos (obviamente, todo sería a través de SSL).
Además de crear los servicios web, también construiré una aplicación cliente (web) que use estos servicios en nombre de un usuario, pero no quiero que la aplicación tenga que almacenar información de usuario / credenciales / etc. Entonces, algo como esto:
Usuario (se autentica con correo electrónico / contraseña o credenciales de terceros) -> Aplicación web (se autentica con ID de aplicación) -> Servicios web
Y de nuevo, quiero permitir que otros creen clientes, así que el nivel medio puede ser cualquier aplicación de terceros:
Usuario (se autentica con correo electrónico / contraseña o credenciales de terceros) -> aplicación de terceros (se autentica con ID de aplicación) -> servicios web
Mis requisitos muy superiores son:
- Seguro (obviamente)
- Credenciales nativas
- Soporte para credenciales de terceros (Google, Yahoo, LinkedIn, etc.)
- Admite múltiples clientes (aplicación web, aplicación móvil, aplicaciones de terceros, etc.)
- Credenciales del cliente (solo una ID de la aplicación?)
- Sesiones de inicio de sesión que caducan
- NO se requiere autorización
Entonces, mi pregunta es, en base a lo anterior (por favor avíseme si esto es demasiado vago), ¿hay un "mejor" enfoque? ¿Son apropiados OAuth o OpenID, o estoy haciendo esto demasiado complicado, y en su lugar debería simplemente rodar mi propia autenticación?
EDITAR:
Creo que tendré que implementar lo siguiente:
1) credenciales / tokens nativos (autenticación básica HTTP sobre SSL?)
2) Una "Parte que confía" de OpenID para permitir que mi API use OpenID alojados en otro lugar (es decir, "soporte para credenciales de terceros")
3) Un "consumidor" de OAuth para permitir que mi API acceda a servicios de terceros (como acceder al perfil de LinkedIn de un usuario).
4) Un "proveedor" de OpenID para permitir que las personas usen las ID nativas de la API en otro lugar (opcional)
5) Un "proveedor" de OAuth para permitir que aplicaciones de terceros accedan a mi API en nombre de los usuarios (opcional)
¿Esto parece correcto, o estoy haciendo esto más complicado de lo necesario?
Implementé y lancé como código abierto un servicio básico que permite la autenticación, puede cambiarse fácilmente para permitir el inicio de sesión de 3 tuplas si es necesario. Tiene alrededor de 2 años y está escrito en Java durante la primavera, por lo que es posible que desee reconsiderar la tecnología, pero funciona y puede obtener la idea básica de cómo se hace. Encuéntrelo aquí en google , o siga las publicaciones de mi blog al respecto. Tenga en cuenta que la aplicación ya no se carga en las nubes, pero si la configura en su cuenta todo debería estar bien.
Mi sugerencia es autenticar la primera solicitud y luego configurar un token de sesión.
La aplicación de front-end almacenaría el token y lo proporcionaría con cada solicitud posterior.
El token tendrá un tiempo de caducidad. El token caducará si no se usa durante cierto período.
El token se puede asociar con la dirección IP de origen para mayor seguridad.
El token se puede transmitir como cookie, o como uno de los parámetros de consulta en URL.
Si la molestia de la autenticación del cliente SSL es aceptable, puede usar la autenticación SSL mutua. Cada cliente debería contar con un certificado en el que confíe el servidor. Puede ser el mismo certificado o diferentes certificados si debe tratar a los clientes de manera diferente.
Podría considerar JWT (JSON Web Token) ver JWT draft rfc . Ciertamente cumpliría con los requisitos de seguridad y vencimiento de la sesión. Sin embargo, al ser un borrador de norma es poco probable que se use ampliamente en este momento, esto podría cambiar pronto ya que JWT forma parte de OAuth 2.0. Los JWT son fáciles de implementar en la mayoría de los idiomas y ya hay muchas bibliotecas. Como explicación simple, un token JWT consta de 3 partes, el encabezado, el cuerpo y la firma. El encabezado y el cuerpo son objetos json codificados en basee64url (los alfabetos difieren de base64 por los 2 últimos caracteres) y luego firmados con HMAC256 (u otro algoritmo especificado en el encabezado); el RFC explica cómo generar exactamente esta firma. Es posible que desee comprobar este generador de tokens en línea .
JWT son encabezados http y parámetros de consulta amigables.
Puede usar HTTP Basic Auth, donde la contraseña transferida no es en realidad una contraseña, sino un token, que el cliente adquirió en una solicitud de recursos diferente, donde tuvo que proporcionar su contraseña una y solo una vez ( tal vez incluso en un canal diferente). Esto no asegura los ataques de hombre en el medio (ya que no hay firma de mensaje), pero la idea es que siempre se puede requerir que el cliente genere un token dinámico de alguna manera (es decir, en un servicio de autenticación propio) y luego haga que envíe ese token como reemplazo de contraseña, por lo que la contraseña real no se transfiere constantemente por el cable. Sí, parece una de las "soluciones de autenticación personalizadas", pero en realidad no es porque pueda imponer las reglas que quiera en la contraseña-token, como usar un token de firma como la contraseña que está vinculada a la sesión o recalculada en cada solicitud (sin compartir ningún secreto) para que el servidor pueda validar el mensaje, sean cuales sean sus necesidades. la idea es enviar el token de validación como la "contraseña" de la solicitud HTTP Auth Authentic y no depender de protocolos más complicados, sin descartarlos (a su elección).
Según sus requisitos, creo que OAuth 2.0
podría ser una opción interesante. OAuth es, de hecho, un protocolo de autorización, pero también Authenticates
al cliente con un clientId
y clientSecret
. Puede utilizar el Client Credential Flow
del Client Credential Flow
y elige no incluir un Refresh Token
, de esta forma el usuario tiene un Access Token
que caduca después de un cierto período de tiempo. Y dado que OAuth es un protocolo ampliamente utilizado, ya hay muchas bibliotecas de cliente y servidor para que usted y sus clientes las utilicen.
Si crees que OAuth es demasiado pesado o complicado para tu aplicación, probablemente me quede con la Basic Authentication
través de HTTPS
. Pero como también dije en otra respuesta a una pregunta similar, nunca inventaría mi propio mecanismo de autenticación.
Para obtener más información, también puede echar un vistazo a la otra respuesta que he dado anteriormente a una pregunta similar: https://.com/a/15003777/849741
Sugiero usar Spring Boot para sus servicios web RESTful porque entonces puede usar Spring Security para implementar su propia autenticación personalizada basada en sus plantillas. Puede implementar su propia autenticación personalizada extendiendo o implementando sus clases e interfaces de seguridad base, respectivamente. También tiene la opción de incorporar esos otros mecanismos de autenticación que haya enumerado en Spring Boot si es necesario.
Una de las buenas opciones a considerar es ''Autenticación de clave compartida''. Este es el tipo de autenticación que usa el servicio web de Amazon y el servicio de almacenamiento de Windows Azure. Hemos utilizado la Autenticación de clave compartida en el servicio REST que desarrollamos. Puede hacer una búsqueda rápida en Google para ''Autenticación de clave compartida'', obtendrá muchos detalles.
Escribí una publicación en el blog here sobre esto.
Los pasos de alto nivel son:
- El cliente combina un conjunto de datos únicos (elementos) definidos por el servicio REST.
- Firme estos datos combinados utilizando una clave que solo conoce el cliente y el servicio REST
- Enviar esta firma al servicio REST como valor para el encabezado HTTP
- El servicio REST calcula la firma exactamente de la misma manera que el cliente
- Compare la firma enviada por el cliente con la calculada, si la misma asume que es una solicitud válida, de lo contrario, denegará la solicitud.