appauth - Crear una API para aplicaciones móviles-Autenticación y autorización
authentication rest (5)
Visión de conjunto
Estoy buscando crear una API (REST) para mi aplicación. El propósito inicial / principal será el consumo de las aplicaciones móviles (iPhone, Android, Symbian, etc.). He estado investigando diferentes mecanismos de autenticación y autorización para API basadas en web (estudiando otras implementaciones). Tengo mi cabeza alrededor de la mayoría de los conceptos fundamentales, pero todavía estoy buscando orientación en algunas áreas. Lo último que quiero hacer es reinventar la rueda, pero no encuentro ninguna solución estándar que se ajuste a mis criterios (sin embargo, mi criterio puede ser equivocado, así que no dudes en criticarlo también). Además, quiero que la API sea la misma para todas las plataformas / aplicaciones que la consuman.
oAuth
Voy a seguir adelante y desechar mi objeción a OAuth ya que sé que probablemente será la primera solución que se ofrezca. Para aplicaciones móviles (o más específicamente aplicaciones no web), parece incorrecto dejar la aplicación (para ir a un navegador web) para la autenticación. Además, no hay forma (estoy consciente) de que el navegador devuelva la devolución de llamada a la aplicación (especialmente multiplataforma). Conozco un par de aplicaciones que hacen eso, pero se siente mal y da un respiro en la aplicación UX.
Requisitos
- El usuario ingresa el nombre de usuario / contraseña en la aplicación.
- Cada llamada API es identificada por la aplicación que llama.
- La altura se mantiene al mínimo y el aspecto de autenticación es intuitivo para los desarrolladores.
- El mecanismo es seguro tanto para el usuario final (sus credenciales de inicio de sesión no están expuestas) como para el desarrollador (sus credenciales de aplicación no están expuestas).
- Si es posible, no requiera https (de ninguna manera un requisito difícil).
Mis pensamientos actuales sobre la implementación
Un desarrollador externo solicitará una cuenta API. Recibirán un apikey y apisecret. Cada solicitud requerirá como mínimo tres parámetros.
- apikey - dado al desarrollador en el registro
- marca de tiempo: se dobla como un identificador único para cada mensaje para un apikey dado
- hash - un hash de la marca de tiempo + el apisecret
El apikey es necesario para identificar la aplicación que emite la solicitud. La marca de tiempo actúa de manera similar al oauth_nonce y evita / mitiga los ataques de repetición. El hash garantiza que la solicitud fue realmente emitida por el propietario del apikey determinado.
Para las solicitudes autenticadas (realizadas en nombre de un usuario), aún estoy indeciso entre ir con una ruta access_token o un combo hash de nombre de usuario y contraseña. De cualquier manera, en algún momento se requerirá un combo de nombre de usuario / contraseña. Entonces, cuando lo haga, se usará un hash de varias piezas de información (apikey, apisecret, timestamp) + la contraseña. Me encantaría recibir comentarios sobre este aspecto. FYI, primero tendrían que codificar la contraseña, ya que no guardo las contraseñas en mi sistema sin hash.
Conclusión
Para su información, esta no es una solicitud de cómo construir / estructurar la API en general, solo cómo manejar la autenticación y autorización únicamente desde una aplicación.
Pensamientos Aleatorios / Preguntas Extra
Para las API que solo requieren un apikey como parte de la solicitud, ¿cómo se evita que otra persona que no sea el propietario del apikey pueda ver el apikey (desde que se envió sin modificaciones) y hacer solicitudes excesivas para exceder los límites de uso? Tal vez estoy pensando en esto, pero ¿no debería haber algo para autenticar que se verificó una solicitud al propietario del apikey? En mi caso, ese fue el propósito del apisecret, nunca se muestra / transmite sin ser hasheado.
Hablando de hashes, ¿qué pasa con md5 vs hmac-sha1? ¿Realmente importa cuando todos los valores se procesan con datos suficientemente largos (es decir, apisecret)?
Anteriormente, estaba considerando agregar una sal por usuario / fila al hash de contraseñas de mis usuarios. Si tuviera que hacer eso, ¿cómo podría la aplicación ser capaz de crear un hash coincidente sin conocer la sal utilizada?
Entonces, ¿qué está buscando es algún tipo de mecanismo de autenticación del lado del servidor que manejará los aspectos de autenticación y autorización de una aplicación móvil?
Asumiendo que este es el caso, entonces lo abordaría de la siguiente manera (pero solo porque soy un desarrollador de Java para que un chico de C # lo haga de manera diferente):
El servicio RESTful de autenticación y autorización
- Esto funcionará solo a través de HTTPS para evitar escuchas ilegales.
- Se basará en una combinación de RESTEasy , Spring Security y CAS (para inicio de sesión único en múltiples aplicaciones).
- Funcionará con ambos navegadores y aplicaciones cliente habilitadas para la web
- Habrá una interfaz de administración de cuentas basada en la web para permitir a los usuarios editar sus detalles, y administradores (para aplicaciones particulares) para cambiar los niveles de autorización.
La biblioteca / aplicación de seguridad del lado del cliente
- Para cada plataforma compatible (por ejemplo, Symbian, Android, iOS, etc.) cree una implementación adecuada de la biblioteca de seguridad en el idioma nativo de la plataforma (por ejemplo, Java, ObjectiveC, C, etc.)
- La biblioteca debe gestionar la formación de solicitudes HTTPS utilizando las API disponibles para la plataforma determinada (por ejemplo, Java usa URLConnection, etc.)
- Los consumidores de la biblioteca de autenticación y autorización general (''eso es todo lo que hay) codificarán en una interfaz específica y no estarán contentos si alguna vez cambia, así que asegúrese de que sea muy flexible. Siga las opciones de diseño existentes, como Spring Security.
Entonces, ahora que la vista desde 30,000 pies está completa, ¿cómo se hace? Bueno, no es tan difícil crear un sistema de autenticación y autorización basado en las tecnologías enumeradas en el lado del servidor con un cliente de navegador. En combinación con HTTPS, los marcos proporcionarán un proceso seguro basado en un token compartido (generalmente presentado como una cookie) generado por el proceso de autenticación y utilizado siempre que el usuario desee hacer algo. Este token es presentado por el cliente al servidor cada vez que se realiza una solicitud.
En el caso de la aplicación móvil local, parece que busca una solución que haga lo siguiente:
- La aplicación cliente tiene una Lista de control de acceso (ACL) definida que controla el acceso en tiempo de ejecución a las llamadas a métodos. Por ejemplo, un usuario determinado puede leer una colección desde un método, pero su ACL solo permite el acceso a objetos que tienen una Q en su nombre, por lo que el interceptor de seguridad retira silenciosamente algunos datos de la colección. En Java esto es sencillo, solo usa las anotaciones de Spring Security en el código de llamada e implementa un proceso de respuesta de ACL adecuado. En otros idiomas, está solo y probablemente necesite proporcionar un código de seguridad repetitivo que llama a su biblioteca de seguridad. Si el lenguaje admite AOP (Programación Orientada a Aspectos), úselo al máximo para esta situación.
- La biblioteca de seguridad almacena en caché la lista completa de autorizaciones en su memoria privada para la aplicación actual para que no tenga que permanecer conectada. Dependiendo de la duración de la sesión de inicio de sesión, esta podría ser una operación única que nunca se repite.
Hagas lo que hagas, no trates de inventar tu propio protocolo de seguridad , o usa seguridad por oscuridad. Nunca podrá escribir un mejor algoritmo para esto que los que están actualmente disponibles y libres. Además, las personas confían en algoritmos bien conocidos. Por lo tanto, si dice que su biblioteca de seguridad proporciona autorización y autenticación para aplicaciones móviles locales mediante una combinación de tokens encriptados SSL, HTTPS, SpringSecurity y AES, inmediatamente tendrá credibilidad en el mercado.
Espero que esto ayude, y buena suerte con su empresa. Si desea obtener más información, hágamelo saber: he escrito bastantes aplicaciones web basadas en Spring Security, ACL y similares.
Esas son muchas preguntas en una, creo que muchas personas no lograron leer hasta el final :)
Mi experiencia con la autenticación del servicio web es que las personas generalmente lo sobreingeniería y los problemas son los mismos que encontraría en una página web. Las posibles opciones muy simples incluirían https para el paso de inicio de sesión, devolver un token, requerir que se incluya con futuras solicitudes. También puede usar la autenticación http básica y simplemente pasar cosas en el encabezado. Para mayor seguridad, gire / expire los tokens con frecuencia, compruebe que las solicitudes provienen del mismo bloque de IP (aunque esto podría ser complicado a medida que los usuarios móviles se mueven entre las celdas), combine con la clave de API o similar. O bien, haga el paso "O solicite la clave" (alguien sugirió esto en una respuesta anterior y es una buena idea) antes de autenticar al usuario, y utilícelo como clave obligatoria para generar el token de acceso.
Una alternativa que aún no he utilizado pero de la que he oído hablar mucho sobre la alternativa amigable para dispositivos a oAuth es xAuth. Eche un vistazo y si lo usa, estaría realmente interesado en escuchar cuáles son sus impresiones.
Para el hashing, sha1 es un poco mejor, pero no te obsesiones: lo que sea que los dispositivos puedan implementar fácilmente (y rápidamente en el sentido del rendimiento) probablemente esté bien.
Espero que ayude, buena suerte :)
La forma en que estoy pensando en hacer la parte de inicio de sesión de esto en mis proyectos es:
antes de iniciar sesión, el usuario solicita un
login_token
del servidor. Estos se generan y almacenan en el servidor a petición, y probablemente tengan una vida útil limitada.para iniciar sesión, la aplicación calcula el hash de la contraseña de los usuarios, luego modifica la contraseña con
login_token
para obtener un valor, luego devuelve tanto ellogin_token
como el hash combinado.El servidor comprueba que
login_token
es uno que ha generado, eliminándolo de su lista delogin_token
válido s. El servidor combina el hash almacenado de la contraseña del usuario con ellogin_token
y garantiza que coincida con el token combinado enviado. Si coincide, has autenticado a tu usuario.
Las ventajas de esto son que nunca almacena la contraseña del usuario en el servidor, la contraseña nunca se pasa a la vista, el hash de la contraseña solo se transfiere en forma clara en la creación de la cuenta (aunque puede haber formas de evitarlo), y debe ser a salvo de los ataques de reproducción ya que login_token
se elimina de la base de datos en uso.
Súper tarde para la fiesta, pero quería agregar algunos puntos adicionales para considerar para cualquier persona interesada en este tema. Trabajo para una empresa que hace soluciones de seguridad de API móvil ( approov ) así que toda esta área es definitivamente relevante para mis intereses.
Para empezar, lo más importante a considerar cuando se trata de proteger una API móvil es cuánto vale para usted . La solución correcta para un banco es diferente a la solución correcta para alguien que solo hace cosas por diversión.
En la solución propuesta, menciona que se requerirá un mínimo de tres parámetros:
- apikey - otorgado al desarrollador al registrarse
- marca de tiempo: se dobla como un identificador único para cada mensaje para un apikey dado
- hash - un hash de la marca de tiempo + el apisecret
La consecuencia de esto es que para algunas llamadas API no se requiere nombre de usuario / contraseña. Esto puede ser útil para aplicaciones en las que no desea forzar el inicio de sesión (por ejemplo, navegar en tiendas en línea).
Este es un problema ligeramente diferente al de la autenticación de usuario y se parece más a la autenticación o certificación del software. No hay ningún usuario, pero aún desea asegurarse de que no haya acceso malicioso a su API. Por lo tanto, usa su secreto de API para firmar el tráfico e identificar el código que accede a la API como genuino. El problema potencial con esta solución es que luego debes revelar el secreto dentro de cada versión de la aplicación. Si alguien puede extraer el secreto, puede usar su API, hacerse pasar por su software pero haciendo lo que quiera.
Para contrarrestar esa amenaza, hay muchas cosas que puede hacer dependiendo de qué tan valiosos sean los datos. La ofuscación es una forma simple de dificultar la extracción del secreto. Hay herramientas que lo harán por usted, más aún para Android, pero aún debe tener un código que genere su hash y un individuo suficientemente capacitado siempre puede llamar directamente a la función que hace el hash.
Otra forma de mitigar el uso excesivo de una API que no requiere un inicio de sesión es reducir el tráfico y, posiblemente, identificar y bloquear las direcciones IP sospechosas. La cantidad de esfuerzo que desee realizar dependerá en gran medida de la valía de sus datos.
Más allá de eso, puede comenzar fácilmente a entrar en el dominio de mi trabajo diario. De todos modos, es otro aspecto de asegurar las API que creo que es importante y quería marcar.
Twitter abordó el problema de la aplicación externa en oAuth apoyando una variante que llaman xAuth . Lamentablemente, ya existe una plétora de otros esquemas con este nombre, por lo que puede ser confuso de resolver.
El protocolo es oAuth, excepto que omite la fase de token de solicitud y simplemente emite inmediatamente un par de token de acceso al recibir un nombre de usuario y una contraseña. (Comenzando en el paso E aquí .) Esta solicitud y respuesta iniciales deben estar seguras : envía el nombre de usuario y la contraseña en texto sin formato y recibe el token de acceso y el token secreto. Una vez que se ha configurado el par de tokens de acceso, el intercambio inicial de tokens mediante el modelo oAuth o el modelo xAuth es irrelevante tanto para el cliente como para el servidor durante el resto de la sesión. Esto tiene la ventaja de que puede aprovechar la infraestructura existente de OAuth y tener casi la misma implementación para aplicaciones móviles / web / de escritorio. La principal desventaja es que a la aplicación se le concede acceso al nombre de usuario y la contraseña del cliente, pero parece que sus requisitos exigen este enfoque.
En cualquier caso, quisiera estar de acuerdo con su intuición y la de muchos otros que responden aquí: no intente construir algo nuevo desde cero. Los protocolos de seguridad pueden ser fáciles de iniciar, pero siempre son difíciles de hacer bien, y cuanto más enrevesados sean, menos probable será que los desarrolladores de terceros puedan implementarlos en su contra. Su protocolo hipotético es muy similar a o (x) Auth - api_key / api_secret, nonce, sha1 hashing - pero en lugar de poder usar una de las muchas bibliotecas existentes, sus desarrolladores necesitarán rodar las suyas.