Cómo proteger una API REST solo para aplicaciones móviles confiables

96

¿Cómo me aseguro de que mi API REST solo responda a solicitudes generadas por clientes confiables, en mi caso, mis propias aplicaciones móviles? Quiero evitar solicitudes no deseadas procedentes de otras fuentes. No quiero que los usuarios completen una clave de serie o lo que sea, debería suceder detrás de escena, después de la instalación y sin necesidad de interacción del usuario.

Hasta donde sé, HTTPS es solo para validar que el servidor con el que se está comunicando es quién dice que es. Por supuesto, voy a usar HTTPS para cifrar los datos.

¿Hay alguna manera de lograr esto?

Actualización: el usuario puede realizar acciones de solo lectura, que no requieren que el usuario inicie sesión, pero también pueden realizar acciones de escritura, que requieren que el usuario inicie sesión (Autenticación por token de acceso). En ambos casos, quiero que la API responda a las solicitudes que provienen solo de aplicaciones móviles confiables.

La API también se utilizará para registrar una nueva cuenta a través de la aplicación móvil.

Actualización 2: Parece que hay varias respuestas a esto, pero honestamente no sé cuál marcar como respuesta. Algunos dicen que se puede hacer, otros dicen que no.

Supercélula
fuente
HTTPS usa SSL (y TLS). SSL / TLS se puede usar con la autenticación del cliente.
atk
¿Te refieres a los certificados SSL del lado del cliente? Creo que eso es lo que estoy buscando, excepto que no tengo idea si eso es posible en aplicaciones móviles (Android e iOS). ¿Dónde se guardaría el certificado del cliente? Dispositivo de almacenamiento, memoria?
Supercell
El SSL solo certificará el dispositivo móvil, NO la aplicación móvil.
Morons
@Supercell: agregaré una respuesta
atk

Respuestas:

48

No puedes

Nunca puede verificar una entidad, ninguna entidad , ya sea una persona, un cliente de hardware o un cliente de software. Solo puedes verificar que lo que te están diciendo es correcto, luego asumir la honestidad .

Por ejemplo, ¿cómo sabe Google que estoy iniciando sesión en mi cuenta de Gmail? Ellos simplemente me piden un nombre de usuario y contraseña, verificar que , a continuación, asumir la honestidad , porque quién más tendría esa información? En algún momento, Google decidió que esto no era suficiente y agregó la verificación del comportamiento (en busca de un comportamiento extraño), pero eso todavía depende de que la persona realice el comportamiento y luego valide el comportamiento .

Esto es exactamente lo mismo con la validación del Cliente. Solo puede validar el comportamiento del Cliente, pero no el Cliente en sí.

Entonces, con SSL, puede verificar que el Cliente tenga un certificado válido o no, así que uno simplemente puede instalar su aplicación, obtener el Certificado y luego ejecutar todo el código nuevo.

Entonces la pregunta es: ¿Por qué es esto tan crítico? Si esto es una preocupación real, cuestionaría su elección de un cliente gordo. Tal vez debería ir con una aplicación web (para que no tenga que exponer su API).

Ver también: Derrota de la validación de certificados SSL para aplicaciones de Android

y: ¿Qué tan seguros son los certificados SSL del cliente en una aplicación móvil?

Imbéciles
fuente
1
He usado certificados de cliente en hardware donde el certificado fue almacenado en una unidad encriptada por el sistema operativo. Pero incluso allí, nadie creía que fuera infalible. El objetivo era dificultar a los usuarios ocasionales.
Steven Burnap
1
@Morons: una aplicación web resolvería esto, pero creemos que es más probable que los usuarios usen la aplicación nativa que una aplicación web (corríjame si nuestra suposición es incorrecta). La razón por la cual esto es tan crítico es porque la API le da al usuario acceso a partes de nuestra base de datos, que contiene una gran cantidad de datos que recopilamos durante meses de trabajo. Son datos que otras compañías o usuarios podrían usar fácilmente para sus propios fines. Sin asegurar a los clientes, no sabríamos quién lo estaba usando (contra nosotros).
Supercell
66
Una aplicación web no resuelve el problema. Es bastante trivial modificar cualquier aplicación web del lado del cliente y hacer que haga lo que quiera.
Steven Burnap
55
@Supercell No puede mostrar los datos de alguien y luego evitar que lo compartan. Si no desea que algunos tengan Datos, no se los dé (muestre).
Imbéciles
Estoy de acuerdo pero por diferentes razones. Puede hacerlo si tuviera control sobre los dispositivos, rsa es como en.wikipedia.org/wiki/SecurID . Pero los móviles no son algo que se pueda controlar (podrían aceptar archivos adjuntos como una clave de complemento o algo así).
imel96
31

Estoy seguro de que se siente cómodo tratando con los inicios de sesión de los usuarios y con las comunicaciones a través de SSL, por lo que me centraré en lo que creo que es la parte más interesante de la pregunta: cómo asegurarse de que sus acciones de solo lectura: que no requieren que el usuario se autentique, ¿solo se aceptan desde sus propias aplicaciones cliente?

Antes que nada, existe la desventaja que fNek insinuó en una respuesta anterior: sus aplicaciones cliente están en manos de usuarios potencialmente hostiles. Pueden ser examinados, sus comunicaciones inspeccionadas, su código desmontado. Nada de lo que voy a sugerir le permitirá garantizar que alguien no realice ingeniería inversa a su cliente y abuse de su API REST. Pero debería poner una barrera frente a cualquier intento casual.

De todos modos, un enfoque común es:

  • El cliente contiene un secreto.
  • Al realizar una solicitud, concatena los parámetros de la solicitud con los secretos y genera el resultado hash
  • Este hash se envía con la solicitud y el servidor lo verifica

por ejemplo, imagine una GETsolicitud de/products/widgets

Digamos que el secreto del cliente es "OH_HAI_I_IZ_SECRET"

Concatenar el verbo HTTP, y la URL, y el secreto:

GET/products/widgetsOH_HAI_I_IZ_SECRET

Y tome un hash SHA-1 de eso:

4156023ce06aff06777bef3ecaf6d7fdb6ca4e02

Luego envíelo junto, de modo que la solicitud sería para:

GET /products/widgets?hash=4156023ce06aff06777bef3ecaf6d7fdb6ca4e02

Finalmente, para evitar que alguien al menos reproduzca solicitudes individuales, tome también una marca de tiempo y agréguela a los parámetros y al hash. por ejemplo, ahora, en tiempo Unix, es 1384987891. Agregue eso a la concatenación:

GET/products/widgetsOH_HAI_I_IZ_SECRET1384987891

Hash que:

2774561d4e9eb37994d6d71e4f396b85af6cacd1

Y enviar:

GET /products/widgets?time=1384987891&hash=2774561d4e9eb37994d6d71e4f396b85af6cacd1

El servidor verificará el hash y también verificará que la marca de tiempo esté actualizada (por ejemplo, dentro de los 5 minutos para permitir que los relojes no estén perfectamente sincronizados)

¡Advertencia! Como estás hablando de aplicaciones móviles, existe un riesgo claro de que el teléfono de alguien tenga el reloj equivocado. O zona horaria incorrecta. O algo. Agregar el tiempo al hash probablemente romperá a algunos usuarios legítimos, así que use esa idea con precaución.

Carson63000
fuente
66
Cualquier programador puede entender este mecanismo de hash cuando desmonta el apk.
Punith Raj
8
@PunithRaj exactamente, cubrí eso en el segundo párrafo. "Nada de lo que voy a sugerir le permitirá garantizar que alguien no realice ingeniería inversa a su cliente y abuse de su API REST. Pero debería poner una barrera frente a cualquier intento casual".
Carson63000
para la advertencia, estoy usando UTC en servidor y móvil, esto resuelve el problema, ¿verdad?
Shareef
@ Carson63000 - Entonces, ¿hay una solución concreta? especialmente para la API de registro de usuarios, que debe estar abierta públicamente (un usuario debe registrarse antes de poder iniciar sesión, ya sea en la web o en una aplicación móvil) y puede ser atacada por bots para crear miles de usuarios falsos.
Tohid
17

Para cualquier persona interesada, en Android PUEDE verificar que la solicitud que recibió se haya enviado desde su aplicación.

En resumen, cuando carga su aplicación en Google, la firma, con una clave única que solo conoce usted (y Google).

El proceso de verificación va (ish) así:

  1. su aplicación va a google y solicita token de autenticación
  2. su aplicación envía el token de forma segura a su back-end
    1. su back-end va a google y verifica el token de autenticación que obtuvo de su aplicación.
    2. su back end luego verifica si la clave única que su aplicación ha firmado coincide, de lo contrario significa que esa no era su aplicación ...

el blog completo que lo explica y cómo implementarlo se puede encontrar aquí: http://android-developers.blogspot.co.il/2013/01/verifying-back-end-calls-from-android.html

ndori
fuente
1
Buena respuesta, sin embargo, un usuario malintencionado aún puede falsificar una aplicación con suficiente esfuerzo. pero nada es realmente segura, no es una cuestión de si, sólo una cuestión de tiempo
Mateos
1
Para iOS existe esta opción: enlace Las API de DeviceCheck también le permiten verificar que el token que recibe proviene de un dispositivo Apple auténtico en el que se ha descargado su aplicación
Iwaz
Requiere cuentas (correos electrónicos)
usuario25
5

Ok, vale la pena mencionar antes de comenzar que para la mayoría de las aplicaciones esto es demasiado exagerado. Para la mayoría de los casos de uso, simplemente tener un solo certificado o token válido es más que suficiente. Si implica hacer algo difícil como descompilar su aplicación, incluso la mayoría de los hackers no se molestarán a menos que proporcione algunos datos muy valiosos. Pero bueno, ¿dónde está la diversión en esa respuesta?

Entonces, lo que puede hacer es configurar una criptografía asimétrica similar a la firma digital utilizada para firmar programas. Cada aplicación puede tener un certificado individual emitido por una sola CA y verificado cuando su usuario se conecta. (ya sea cuando se registra por primera vez o cuando se instala por primera vez) Cuando se autentica ese certificado, puede asegurar aún más su aplicación al registrar ese certificado como válido para un identificador de dispositivo dado (como ID de Android )

Tom Squires
fuente
5

Como @Morons mencionó en su respuesta, es muy difícil verificar la entidad en el otro extremo de la conexión.

La forma más sencilla de proporcionar cierto nivel de autenticidad es hacer que el servidor verifique algún secreto que solo la entidad real conocería. Para un usuario, puede ser un nombre de usuario y una contraseña. Para una pieza de software donde no hay usuario, puede incrustar un secreto.

El problema con estos enfoques es que debe confiar un poco en el cliente. Si alguien aplica ingeniería inversa a su aplicación o le roba su contraseña, puede pretender ser usted.

Puede tomar medidas para dificultar la extracción de la información secreta al ofuscarla en el ejecutable. Herramientas como ProGuard, que es un ofuscador para Java, pueden ayudar con esto, no sé mucho sobre la ofuscación en otros idiomas, pero es probable que haya herramientas similares. El uso de una conexión TLS ayuda a evitar que las personas espíen su tráfico, pero no evita un ataque MITM. La fijación puede ayudar a resolver ese problema.

Trabajo para una compañía llamada CriticalBlue (¡divulgación completa!) Que tiene un producto llamado Approov que trata de resolver este problema de confianza. Actualmente funciona para Android / iOS y proporciona un mecanismo para que nuestros servidores verifiquen la integridad de la aplicación cliente. Lo hace haciendo que el cliente calcule una respuesta a un desafío aleatorio. El cliente tiene que calcular la respuesta utilizando los atributos del paquete de la aplicación instalada que son difíciles de falsificar e incluye algunos sofisticados mecanismos anti-manipulación.

Devuelve un token que luego puede enviar como prueba de autenticidad a su API.

La diferencia importante con este enfoque es que, aunque sería posible deshabilitar la comprobación de autenticidad en el cliente, si lo hiciera no obtendría el token de autenticación que necesita para verificar su aplicación con el servidor. La biblioteca también está estrechamente unida a las características del ejecutable en el que se encuentra, por lo que sería muy difícil incrustarla en una aplicación falsa y hacer que funcione.

Hay un análisis de costo / beneficio que cualquier desarrollador de API debe hacer para decidir qué tan probable es que alguien intente piratear su API y cuán costoso puede ser. Una simple verificación secreta en la aplicación evita ataques triviales, pero protegerse contra un atacante más decidido es probablemente mucho más complicado y potencialmente costoso.

El pragmático
fuente
0

SSL asegurará el canal de comunicación.

El inicio de sesión exitoso emitirá un token de autenticación a través de una conexión cifrada.

El token de autenticación se pasará a su API REST en todas las solicitudes posteriores.

CodeART
fuente
1
He agregado información adicional. Estaba planeando hacer la autenticación como mencionaste, con un token de acceso. La API REST no requiere que el usuario inicie sesión, solo para acciones específicas. En ambos casos, los clientes deben ser firmados / de confianza.
Supercell
No sé mucho sobre el desarrollo móvil nativo, pero ¿puede su aplicación móvil proporcionar el número móvil a la API REST? Cuando instalo aplicaciones en mi teléfono Android, a menudo se me pide que otorgue ciertos permisos a la aplicación. Si puede enviar un número de móvil con cada solicitud a través de una conexión segura, puede rechazar todas las solicitudes con un número de móvil desconocido. Solo
estoy
Eso podría funcionar, pero requeriría que el usuario inicie sesión y el número vinculado a la cuenta de usuario. De lo contrario, el servidor no tendría nada para verificar el número.
Supercell
¿Cómo vas a instalar tu aplicación móvil?
CodeART
Estarán disponibles a través de las tiendas de aplicaciones (Google, Apple, Microsoft)
Supercell
0

No sería demasiado seguro, pero podría agregar algún tipo de código secreto o incluso una firma digital. Desventaja: debe incluirse en la aplicación, lo que facilita su obtención si sabes lo que haces.

fNek
fuente
0

Hasta donde sé, HTTPS es solo para validar que el servidor con el que se está comunicando es quién dice que es.

De hecho, puede usar SSL para autenticar tanto al cliente como al servidor. O, dicho de otra manera, "sí, puede usar certificados de cliente".

Tendrás que ...

  • mire la biblioteca SSL que está utilizando para determinar cómo especificar certificados de cliente en el dispositivo móvil,
  • escriba código o configure su servidor HTTPS para que solo acepte conexiones de clientes confiables y registrados.
  • idear un mecanismo para agregar certificados de clientes confiables en su servidor
  • idear un mecanismo para eliminar los certificados de cliente que ya no son de confianza de su servidor

Puede hacer que la aplicación móvil almacene el certificado donde lo desee. Dado que desea la autenticación específica de la aplicación, debe considerar almacenar el certificado en una ubicación de disco protegida (en Android, puede crear una tabla de "configuración" en su base de datos SQLite, y una fila para su certificado y otra para su clave privada) .

atk
fuente