¿Cómo diseñar la autenticación de usuario desde las aplicaciones cliente?

14

He estado desarrollando una aplicación que admitirá muchos usuarios. Lo que pasa es que no puedo entender cómo autenticar al cliente / usuario.

Estoy creando una aplicación como http://quickblox.com/ donde les daré credenciales a mis usuarios y los usarán para construir N aplicaciones en las que no pueden poner su nombre de usuario y contraseña para autenticarse.

Supongamos que va de la siguiente manera. (Al igual que QuickBlox)

1. El usuario crea una cuenta en mi sitio web.
2. El usuario puede crear claves N API y secretar credenciales. (Para múltiples aplicaciones)
3. El usuario usará estas credenciales en sus aplicaciones (Android, iOS, Javascript, etc.) para hablar con mis API REST.
(Las API REST tienen acceso de lectura y escritura).

¿Mi preocupación?

Los usuarios pondrán sus credenciales (clave API y clave secreta) en las aplicaciones que creen, ¿qué sucede si alguien obtiene estas claves e intenta imitar al usuario? (Descompilando APK o buscando directamente en el código JavaScript.

¿Me equivoco en alguna parte?
Estoy confundido con el arquitecto de este mecanismo de usuario de tres niveles.

Alok Patel
fuente
Lo que parece estar tratando de hacer no es posible.
user253751
Existen muchas aplicaciones que hacen lo mismo. No estoy seguro de cómo autentican a los usuarios.
Alok Patel
¿Está intentando autenticar la aplicación cliente o el usuario ? Muchas aplicaciones autentican a los usuarios. Ninguno de ellos autentica las aplicaciones del cliente de una manera irrompible.
user253751
Sí, por cliente quiero decir que solo quiero autenticar al usuario.
Alok Patel el
44
Ah, bueno, entonces, en el sistema de autenticación más típico, solo hace que el usuario ingrese su nombre de usuario y contraseña, y los envíe de forma segura al servidor que los verifica y (de forma segura) devuelve un token de sesión, y luego envía el token de sesión cada solicitud futura
user253751

Respuestas:

7

He estado diseñando API REST durante los últimos años. Te estás preocupando demasiado. Recientemente, otro usuario en este foro hizo una pregunta, donde le preocupaba almacenar puntos finales URI en su código JavaScript del lado del cliente .

Se aplican las mismas reglas que se aplican al desarrollador de JavaScript. Si permite que personas externas integren su API, su API tiene la misma visibilidad que un sitio web normal y debe tratarla de la misma manera.

Cita de la respuesta original:

Cuando crea un sitio web y no desea que los usuarios hagan algo, no implementa esa funcionalidad ni prohíbe que ciertos usuarios la utilicen. Con una API REST que debería tener puntos finales públicos, es prácticamente lo mismo, debe tratarla como un sitio web público.

Su API REST debe ser lo suficientemente robusta como para no permitir operaciones no válidas, como el acceso a datos de un usuario diferente.

Debe diseñar los tokens de acceso de la aplicación para permitir solo las operaciones que desea permitir. Podría tener dos tipos de tokens de acceso:

  • token maestro : podría ser utilizado por el creador de la aplicación y proporcionar más funcionalidad desde su API,
  • token de aplicación : el token que en realidad se almacenaría dentro de las aplicaciones y que solo tendría acceso limitado a su API, solo a operaciones que no pueden corromper la suya o los datos del programador de la aplicación.

Pero, ¿qué alguien deconstruye el código fuente, quita los tokens de la aplicación, descubre cuáles son los puntos finales públicos y abusa de su servicio web?

A menos que esté administrando directamente el desarrollo de las aplicaciones que consumen su API, nada realmente prohíbe que las personas abusen de su API de la misma manera directamente desde la aplicación.

Andy
fuente
Buena explicación hasta ahora, aunque tengo una pregunta. Digamos que una de mis API está construida para obtener todos los datos relacionados (A + B) de mi usuario . Mi usuario usa esta API en su aplicación para obtener solo la filtered data(B) de su usuario . Ahora es posible, o hay alguna solución para evitar que un tercer usuario robe todos los datos (A + B) de mi usuario . ¿Tiene sentido?
Alok Patel
@AlokPatel No hay otra solución para simplemente no implementar la funcionalidad. Cuando lo haces, siempre existe el riesgo de que alguien falsifique su hash de identidad para parecerse a otra persona. Programáticamente su problema no puede resolverse. Como he dicho, si no desea ofrecer alguna funcionalidad, no la implemente. Dado que las aplicaciones probablemente almacenarán el hash de inicio de sesión dentro de ellas, una vez que se implemente la aplicación, también lo será su clave API y no estará disponible públicamente.
Andy
Gracias por la explicación. Entonces, lo que obtuve hasta ahora es que las API REST son las mismas que cualquier sitio web que implementamos, son tan abiertas como el sitio web. Si no quiero que el usuario haga algo, simplemente no lo implemento en mis API REST. Entonces, lo que puedo hacer es tener claves separadas para las bibliotecas del cliente (Android, iOS, JS) que pueden verse comprometidas con menos funcionalidad y diferentes claves que se usarán en el lado del servidor (PHP, Java, node.js) con una funcionalidad extendida. Espero que esto funcione!
Alok Patel
¿Me puede explicar su este punto? A menos que esté gestionando directamente el desarrollo de las aplicaciones que consumen su API
Alok Patel
@AlokPatel Lo que quise decir es que en este momento te preocupa que le des a alguien acceso a la API, pueden distribuir el acceso y comenzar a abusar de la API. Si no tiene control sobre el desarrollo de las aplicaciones que consumen su API, podrían hacer lo mismo incluso por su cuenta.
Andy
5

Su problema no es tanto técnico como comercial.

Digamos que tiene su API, que vende a sus clientes (los desarrolladores de la aplicación) por una tarifa plana de £ 100 al año, acceso ilimitado.

Bueno, obviamente, puedo comprar su servicio a £ 100 y venderlo a 10 personas a $ 50 cada uno. ¡No quieres eso! así que intenta pensar en una restricción que le permita vender su API sin que esté abierta al arbitraje.

  • Si solo restringe la cantidad de aplicaciones, un cliente puede crear una sola aplicación que acepte conexiones de otras aplicaciones y las transfiera.

  • Si limita a los usuarios, nuevamente, el cliente puede ocultar usuarios detrás de su propia autenticación y parecer un solo usuario.

Lo que debe hacer es pasar el costo de cada llamada API a su cliente. es decir, cobrar por llamada API o establecer una cuota de llamadas por año.

Esto empuja el mismo problema de arbitraje a sus clientes. Los obliga a adoptar medidas para evitar que sus usuarios roben sus claves. En este caso, esconde tu API detrás de su propia API autenticada por el usuario.

Ewan
fuente
Ya he planeado limitar el uso de mi API en función de la cantidad de llamadas a la API, por lo que el problema relacionado con el negocio no es mi preocupación en este momento, solo me preocupa que me roben las llaves.
Alok Patel
Desde el punto de vista comercial, el problema no tiene solución. Lamentablemente, tampoco puede resolverlo mediante programación.
Andy
1
El problema comercial se resuelve cobrando por llamada. Si le roban la llave, su cliente pierde. No tú. Simplemente déle a su cliente una forma de cancelar las llaves robadas y dígale que tiene una API intermedia para evitar abusos
Ewan
2

Las otras respuestas parecen sugerir que el problema de almacenar un secreto en una aplicación en dispositivos de consumo no se puede resolver.

Claro que lo es.

Dos principios (se seguirán los detalles de implementación):

  1. Los puntos finales de autenticación reales deben estar abiertos de forma anónima al público.
  2. El servidor debe de alguna manera participar en la autenticación del cliente y proporcionar una clave API.

Dado que, si el cliente realiza una solicitud al punto final de autenticación con credenciales, y el servidor la autentica, el servidor puede generar un token temporal dinámico (temporal, lo que significa tiempo). Este token debe recordarse dentro del cliente y enviarse con solicitudes posteriores.

Necesitará un mecanismo para "actualizar" periódicamente el token, es decir, obtener uno nuevo. Simplemente cree un punto final REST que permita generar un nuevo token a partir de uno existente, para evitar tener que volver a autenticarse a partir de credenciales.

Si está tratando de evitar que el usuario final se vuelva a autenticar, entonces esta autenticación puede ser una configuración inicial única en la aplicación cuando se instala.

Esta solución simplemente evita la necesidad de almacenar un token estático incrustado dentro del binario de la aplicación. El servidor genera un token sobre la marcha solo en respuesta a una autenticación exitosa. Para que un usuario malintencionado inspeccione su aplicación e intente obtener acceso no autorizado a la API, aún necesitará autenticarse como cualquier otra persona.

Brandon
fuente
Solución interesante, aunque se basa principalmente en cómo los clientes del OP codificarán su aplicación. Dicho esto, el enfoque propuesto podría permitir almacenar el lado del servidor de claves API y, después de una autenticación exitosa de sus propios usuarios, podría reenviar la clave temporal para que la aplicación real la use. De esta manera, nada se almacena en la aplicación.
Newtopian
Eso es cierto para todas las API. Si un consumidor de API no lo consume correctamente, es posible que las cosas no funcionen. Esto tendría que ser una parte documentada de la API.
Brandon
Por cierto, hay estándares para ayudar a hacer esto más fácil, como OAuth.
Brandon
0

Si tiene claves únicas por aplicación, puede usarlas solo durante una autenticación de conexión inicial, iniciada por el cliente, luego de lo cual cambia a un token de autenticación único por aplicación.

Su servidor cambia (lanza) el token para cada aplicación cliente de vez en cuando (periódicamente más / menos algún retraso difuso / aleatorio aleatorio, por ejemplo). El token móvil solo es conocido entre el servidor y el cliente autenticado.

Los nuevos tokens se devuelven a cuestas en las respuestas regulares. Cada vez que la respuesta contiene un nuevo token, la aplicación receptora debe cambiar para usarla en solicitudes posteriores.

Cada vez que el intercambio con un cliente no esté sincronizado (algún error de protocolo de algún tipo) su servidor solicitará una nueva autenticación (a través de una respuesta de error a la siguiente solicitud del cliente, o respaldado en la respuesta válida a la solicitud del cliente, para ejemplo).

La autenticación inicial iniciada por los clientes mientras se usa activamente un token rodante debe considerarse con sospecha; podría muy bien ser un intento de imitación. Solo lo permitiría si el intercambio permanece inactivo durante un intervalo más largo de lo esperado, que podría, por ejemplo, ser causado por una interrupción / reinicio del cliente con una nueva instancia que no tiene el token rodante.

Sería aún mejor persistir el token en el lado del cliente para que un cliente reiniciado pueda continuar desde donde se fue su predecesor, lo que reduce significativamente la apertura para imitar.

Tal esquema haría que imitar al menos fuera bastante difícil: el cliente que imita tendría que predecir exactamente la ventana cuando el cliente autorizado deja de enviar solicitudes el tiempo suficiente para que el servidor decida que está bien aceptar que se pueda realizar una nueva autenticación de cliente con la clave prescrita. Tales solicitudes fuera de la ventana permitida se pueden usar como detección de intentos de imitación y posiblemente iniciar algunas contramedidas (listas negras de IP, etc.).

Dan Cornilescu
fuente
0

Por lo que sé, lo que mencionaste es la única forma de hacer esto. La aplicación que almacena la clave definitivamente es un riesgo, pero hay varias formas de eludirla. Siempre puede usar el almacén de claves para almacenar la clave, en lugar de codificar, forzando así un inicio de sesión único.

Además, debe considerar vincular una clave a un cliente, por lo tanto, si alguien imita, debe tener una capa de seguridad para verificar el cliente, la clave y los agentes de usuario para bloquear la solicitud de inmediato. Tenga un caso de uso para volver a emitir o asegurar que las claves no se imitan.

Arun
fuente
¿Qué es la solución para JavaScript? ¿Cómo diseñar para eso?
Alok Patel el
Supongo que está hablando de crear una aplicación híbrida. Si ese es el caso, definitivamente debería poder crear un complemento para almacenar las claves. Si va a alojar la aplicación y habla de una solución web móvil, piense en representar la página con un contenedor y puede confiar en un token de sesión sugerido anteriormente
Arun
No, no es el caso. Sería el tercer proveedor principal de API, mis usuarios usarán mi servicio de API en sus aplicaciones. Puede ser Android, iOS, JavaScript, etc ...
Alok Patel
0

Si depende de dar tokens de autorización a sus clientes para que pongan sus aplicaciones, siempre será teóricamente posible que alguien realice una ingeniería inversa de la aplicación y la extraiga. Para evitar esto, necesitará un mecanismo que no requiera un secreto dentro de la aplicación cliente. Eso es complicado Sin embargo, puedo sugerirte algunas opciones para que pienses.

Tiene un problema una vez que ha entregado las credenciales, no tiene control sobre la seguridad con la que se almacenan. Además, si requiere que el usuario le envíe las credenciales, alguien puede MITM su conexión y robar los tokens directamente sin preocuparse por la ingeniería inversa de la aplicación.

Una forma de hacer que sea más difícil extraer su token de autorización es ofuscarlo. Esto solo sube el listón, pero no lo hace imposible, y para hacerlo tendrías que mantener el control del secreto. Puede implementar una biblioteca que contenga la información secreta y sea específica para cada cliente. Puede usar la biblioteca para comunicarse con sus servidores y es posible que ni siquiera tenga que decirle a su usuario la información secreta, simplemente podría estar incrustada en la biblioteca. Esto no resuelve el problema de que alguien realice ingeniería inversa en su biblioteca, pero sí le permite controlar el nivel de ofuscación. Un inconveniente es que una vez que una persona ha roto la ofuscación en la biblioteca, puede atacar cualquier biblioteca tuya, a menos que escribas un código que haga que cada biblioteca sea significativamente diferente. Eso introduce su propio conjunto de problemas.

Esto puede alejarse un poco del alcance de su pregunta, pero está relacionado con la seguridad de su token, por lo que lo mencionaré. Para evitar el robo trivial del token a través del cable, probablemente no desee enviar el token directamente, en su lugar, puede firmar el tráfico utilizando una función HMAC. Puede verificar la validez del mensaje calculando el HMAC del mensaje en el servidor y comparándolo con el HMAC enviado desde el cliente. Usaría el token como la clave de la función HMAC para que solo alguien que conozca el token pueda firmar el tráfico. Esto es mejor para la seguridad de su token porque nunca lo envía directamente al servidor, por lo que no puede ser interceptado y robado directamente. Para obtener más información sobre HMACS, consulte esta pregunta: /security/20129/how-and-when-do-i-use-hmac/20301

Ninguna solución de seguridad será inexpugnable, debe decidir cuánto le costará implementar frente a la probabilidad y el costo de verse comprometido.

El pragmático
fuente
No puedo hacer una biblioteca y ponerle secretos, serán diferentes para cada uno de mis usuarios.
Alok Patel el
Para aclarar, estaba sugiriendo que podría construir una biblioteca personalizada para cada uno de sus usuarios y ocultar sus secretos individuales dentro de la biblioteca. Debería escribir un sistema para generar las bibliotecas automáticamente a pedido para cada nuevo usuario, lo que puede ser más trabajo del que desea.
ThePragmatist
0

Citando a ti mismo:

No puedo entender cómo autenticar al cliente / usuario ... en el que no pueden poner su nombre de usuario y contraseña para autenticarse.

Ahora que es una contradicción, ¿no? ;)

Como otros dijeron, no puedes. Si una aplicación usa una clave API, se puede descompilar como usted dice para obtener la (s) clave (s) y usarla también.

Además de requerir una autenticación de usuario adecuada adicional, solo puede limitar el daño:

  • IP de lista blanca / lista negra
  • estrangulamiento
  • detección de "actividad inusual" y su fuente
  • renovación fácil de llaves
dagnelies
fuente