Asegurando una API REST: ¿api_secret está firmando y es suficiente con SSL?

10

para asegurar una API RESTful pensé en el siguiente procedimiento de autenticación para cada llamada:

  • Todos los datos están cifrados con SSL
  • Cada solicitud HTTP realizada por el cliente tendrá una firma como sha512(keysort(POSTDATA.push({"secret": API_SECRET, "timestamp": utc_time()}))
  • El servidor conoce también a los clientes API_SECRET y comprueba si la firma coincide con la enviada por el cliente. Si ese es el caso, la solicitud es legítima y se procesará.

El problema al que me enfrento aquí es el siguiente: dado que la aplicación de iPhone y la aplicación web llamarán a la API, no puedo pensar en una forma de no transmitir la API_SECRET una vez . Entonces, digamos que el usuario inicia sesión, envía username = john & password = doe (cifrado SSL) y recibe un API_SECRET en respuesta del servidor. El cliente almacenará este API_SECRET y lo utilizará para firmar todas las llamadas API posteriores.

Estoy utilizando la firma para reducir el riesgo de ataques MITM, pero si estoy transfiriendo la clave una vez parece ser un problema, pero no puedo pensar en una manera de resolver esto.

¡Gracias por tu ayuda!

    
pregunta doque 13.08.2012 - 14:30
fuente

2 respuestas

7

Hrm. Además de SSL, no estoy seguro de lo que realmente está obteniendo de API_SECRET aquí.

Pienso que tener un certificado SSL de servidor de una fuente conocida y confiable sería lo mejor que puede hacer aquí, suponiendo que su aplicación cliente se distribuye de una manera confiable. En ese momento, el cliente puede verificar la autenticación del servidor a través de la sesión SSL, y el servidor autentica al cliente con el nombre de usuario / contraseña.

Como dice @Polynomial - SSL debe cifrar la sesión de modo que los ataques MITM entre los puntos finales de SSL no sean un problema. El truco es saber dónde se ubican esos puntos finales y asegurarse de que estén ubicados en su infraestructura en un lugar bien pensado. Por ejemplo, si hay un punto final de SSL frente al servidor de aplicaciones, ¿qué protege esa última milla de transmisión?

Del mismo modo, ¿la aplicación (móvil o web) está comprobando correctamente que el certificado SSL del servidor proviene de una fuente confiable?

Adición para la pregunta en el comentario:

Eché un vistazo a la referencia de clase para NSURLReference en las páginas de desarrollo de Mac y no pude encontrar ninguna referencia a SSL ... de hecho, los comentarios dicen específicamente que es independiente del protocolo, lo cual tiene sentido dado que se llama URL Solicitud.

No creo que puedas asumir que incluso tienes HTTPS con esta clase, tendrás que hacer algo para configurar la sesión de HTTPS en lugar de usar la configuración predeterminada de HTTP. Aquí está la Descripción general del desarrollador de Mac en SSL . Me está molestando un poco, porque no hay una función obvia para obtener el certificado del servidor .

Luego también necesitará la Certificado, clave y confianza servicios - para verificar el certificado.

NO supondría que el entorno de desarrollo de Apple solo hará esto por usted. La experiencia previa con otras API no me ha dado ninguna razón para confiar en esto y no veo la documentación que dice lo que hace explícitamente. Ni siquiera estoy particularmente seguro de cómo funcionan las tiendas de confianza en este entorno de desarrollo. Y este no es un lugar donde quieres hacer suposiciones ciegas. Estudiaría en qué condiciones el entorno fuerza a SSL, verifica la autenticidad de los certificados de servidor y verifica que el certificado esté firmado por una CA de confianza. Si no tiene documentación que le indique cuándo y cómo suceden estas cosas, realmente no puede asumir que su servicio es seguro.

    
respondido por el bethlakshmi 13.08.2012 - 23:32
fuente
9

Aquí se hacen dos preguntas diferentes: sobre el método para generar una "firma" en cada solicitud y sobre el método para aprovisionar el API_SECRET a los clientes en el primer uso. Hablando estrictamente, estas deberían haberse dividido en dos preguntas, pero las responderé a las dos.

Su formato de firma. Usted tiene el concepto básico sobre el derecho, pero tengo algunas sugerencias / críticas constructivas:

  • Use un MAC. Debe usar un código de autenticación de mensaje, no un hash. El uso de un hash, como lo ha hecho, es vulnerable a los ataques de extensión de longitud . Por ejemplo, puede usar MAC (K, D) donde K es su API_SECRET , D son los datos de la solicitud y la marca de tiempo, y MAC es un algoritmo de código de autenticación de mensaje seguro. AES-CMAC es una buena elección de algoritmo MAC. SHA1-HMAC es otra opción estándar.

  • Incluir la marca de tiempo en la solicitud. Probablemente deba incluir la marca de tiempo en la solicitud. El servidor necesita conocer la marca de tiempo utilizada por el cliente para validar la solicitud. Como no puede confiar en que los relojes del cliente y del servidor estén perfectamente sincronizados, deberá enviar la marca de tiempo en la solicitud.

  • Tenga cuidado con los parámetros duplicados. Si tiene dos parámetros de solicitud con la misma clave, puede tener ataques de contaminación de parámetros del host (HPP). Sugiero verificar que las claves sean todas únicas y que la solicitud no tenga ningún parámetro con una clave de secret o timestamp (si va a agregar esos parámetros a los parámetros POST).

  • Cuidado con los problemas de concatenación. No dijiste cómo tomas la lista ordenada de parámetros y los conviertes en una cadena. Los detalles importan. Si solo concatena todos los valores, será vulnerable, ya que el límite entre los campos es ambiguo. Por lo tanto, no use la concatenación; use alguna codificación decodificable sin ambigüedades cuando prepare los datos para la codificación (o la firma por el MAC).

  • Otros recursos. Vea también Cómo implementar un mecanismo de clave API para una pregunta relacionada.

Aprovisionamiento de secretos criptográficos. Por lo tanto, necesita una manera de obtener el API_SECRET para cada cliente. Aquí hay una manera estándar de hacerlo. En el primer inicio de sesión, el usuario escribe su contraseña en el cliente. El cliente abre una conexión SSL con el servidor y envía el nombre de usuario y la contraseña del usuario. El servidor valida las credenciales del usuario y, si son correctas, envía el valor API_SECRET de este usuario al cliente. El cliente ahora almacena el API_SECRET en el almacenamiento privado (pero no almacena la contraseña del usuario). En conexiones posteriores, el cliente ahora puede usar su API_SECRET para autenticarse.

Un enfoque alternativo. Si va a conectarse solo desde clientes dedicados (por ejemplo, una aplicación móvil, una aplicación de escritorio, pero no desde Javascript que se ejecuta en el navegador), entonces puede considerar La siguiente alternativa. En lugar de usar criptografía de clave simétrica, use criptografía de clave pública. En otras palabras, en lugar de usar un API_SECRET , haga que cada cliente genere su propio certificado de cliente SSL. El cliente almacena la clave privada de forma segura. En la primera conexión, el cliente se autentica utilizando la contraseña del usuario y envía su clave pública (en realidad, su certificado), y luego olvida la contraseña del usuario. El servidor recuerda el certificado del cliente y todas las conexiones posteriores se autentican mediante el uso de SSL con certificados del cliente.

Este es un enfoque fuerte. Se encarga de todos los posibles enfoques de seguridad enumerados anteriormente. El único inconveniente es que no puede escribir fácilmente un cliente Javascript / AJAX que se ejecuta en el navegador.

    
respondido por el D.W. 15.08.2012 - 04:06
fuente

Lea otras preguntas en las etiquetas