Autenticación de REST APIs

PiradoIV

Ahí va una para los criptógrafos.

Estoy intentando montar un sistema con una API REST y pretendo usar HMAC para firmar las peticiones. Prometo que he buscado y rebuscado, pero no encuentro una implementación completa, empezando por el registro del usuario hasta una petición final, pasando por el logueo. Así que estoy seguro de que no acabo de entenderlo.

Hasta donde he conseguido trastear, podría crear una comunicación con SSL al servidor para registrar al usuario y guardar su nombre de usuario, email y un hash de la contraseña (con su salt).

  • Supongo que debería generar en el momento de registro un private key completamente aleatorio.
  • ¿Sería seguro comprobar el usuario/contraseña y devolver este private key si la comunicación va sobre SSL?

Una vez que el cliente y el servidor tienen la private key, ya podría seguir trasteando con el resto de cosas que he leído, pero lo que no me queda 100% claro es si el intercambio de esta clave privada es seguro simplemente por SSL o debería hacer más cosas.

En resumen, ¿en qué momento y de qué manera se intercambian las claves privadas?.

Saludos, ¡gracias!

1
LOc0

Hola. Una pregunta, si vas a usar SSL para el API ¿por qué el HMAC en las peticiones? SSL ya se encarga del trabajo "sucio". Yo generaría un API-KEY (puedes sacarla random y guardarla en algún sitio o generarla a partir del hmac del usuario y una clave secreta tuya) Después al hacer las peticiones obligas a dar el user y el API-KEY y compruebas que el API-KEY se corresponde con el usuario.

Salu2 ;)

1 respuesta
elkaoD

#1 ¿realmente necesitas HMAC para firmar las peticiones?

Con SSL va todo seguro. En SSL el punto de fallo es que el usuario sabe que está hablando con el servidor B (certificado) pero el servidor no sabe que está hablando con el usuario A (porque los usuarios no tenemos certificado).

Pero eso es soluciona con contraseña sin necesidad de HMAC ni nada. Una vez el usuario está loggeado puedes asumir que es él sin ninguna duda (a no ser que le hayan robado la clave por medios externos a SSL).

#2 a la vez! xD

1 respuesta
LOc0

#3 Desde que eres merodeador te has vuelto lentorro chaval :P

Salu2 ;)

1 respuesta
PiradoIV

¿y si quisiera hacerlo sin SSL para ahorrar el certificado?

1 respuesta
elkaoD

#4 pero soy un 37% más sexy.

#5 créeme, SSL existe por una razón. Sin SSL va todo en texto plano así que estás en bragas.

Siempre se te pueden ocurrir esquemas paralelos para ahorrarte el certificado pero TODOS fallarán. Te pongo casos de ejemplo:

1. El clásico usuario + contraseña sin SSL

La contraseña va en texto plano por HTTP. Las seguridad es cero.

2. Usuario + contraseña hasheada

Para evitar mandar la contraseña en texto plano, el usuario manda HASH(contraseña)

El problema: aunque la contraseña la envíe hasheada el usuario y el "espía" no pueda ver la contraseña en texto plano, sigues siendo vulnerable a ataques de "replay": el enemigo no tiene más que enviar la contraseña que ya ha visto hasheada en lugar del texto plano.

Seguridad cero.

Si quieres usar salt se lo tienes que enviar al usuario por texto plano primero.

3. Usuario + contraseña hasheada con challenge

Imagino que por aquí va tu idea: el servidor manda pre-login al usuario un token de challenge aleatorio. Este responde con username + HASH(username + contraseña + salt + challenge).

Un oponente pasivo no puede espiar la comunicación, pero nada impide a un oponente activo montar el siguiente esquema:

   Usuario <-> Oponente <-> Servidor

¿Por qué? Como "Usuario" no tiene un certificado de "Servidor" al no estar dado de alta en ninguna CA (autoridad de certificación), no puede saber si verdaderamente está hablando con "Servidor" o con "Oponente haciéndose pasar por Servidor".

Servir tu propio certificado tampoco vale de nada: podría estar forjado. No hay forma de distinguir mi certificado original del de un oponente que dice ser yo, a no ser que haya una CA que valide que uno de los dos certificados es el verdadero.

Puestos a hacer eso, puedes servir tu propio certificado con SSL (con su feo warning gigantesco de "este certificado no está firmado!" que existe precisamente para evitar esto).

Seguridad cero punto cinco.

RPV: usa SSL.

Todo lo que puedas montar va a ser una imitación de SSL y encima limitado porque no tienes certificado.

2 3 respuestas
wineMan

El algoritmo de Diffie-Hellman es la mejor solución existente para intercambiar claves privadas. Por lo visto lleva funcionando desde 1976 y todavía se usa. No parece muy complicado de implementar.

http://www.javiercampos.es/blog/2011/07/22/el-algoritmo-de-diffie-hellman/

Edit: antes de que nadie lo ponga lo pongo yo: El algoritmo Diffie-Hellman es de pobres! Pero sin SSL es lo único que hay.

1 respuesta
B

La mayoria de las restful apis que me he encontrado son SSL + apikey. Puedes implementar más seguridad con handshakes etc pero lo veo complicarle la vida al cliente.

1 respuesta
Amazon

#8

Ahora mantenemos una conversación segura.

LOc0

Veo a #6 y subo con:

Te generas un API-KEY random de 128 bits para el usuario y se la envias a su correo (que esperemos que use SSL :P ) y usáis AES para las peticiones ;) . Y fueron felices y comieron perdices... ¡NOOO!

Aún necesitas guardar un ESTADO de la comunicación para evitar que un man-in-the-middle te haga un replay. Para eso, le mandas un nonce aleatorio al usuario que lo incluirá en su petición cifrada y GL

Salu2 ;)

1 1 respuesta
wineMan

#10 aclarar que #1 no puede enviar email ni usar un canal de ese estilo. Tiene que ser una comunicación instantánea.

elkaoD

#7 Diffie-Hellman sería un paso 4 en #6 pero ni me he molestado en ponerlo porque sigue siendo vulnerable por lo del certificado (es una putada, sin certificado por mucha seguridad que añadas estás en bragas). Me explico:

En primer lugar, Diffie-Hellman sirve para que dos usuarios puedan compartir un secreto y un oponente que escucha no pueda conocerlo. Sin embargo el usuario no está autenticado: el secreto es completamente aleatorio siempre (y si no lo es el protocolo es vulnerable).

Tras el intercambio DH Usuario no sabe nada sobre la identidad de Servidor ni viceversa. Por no saber, no sabe ni la clave que ha usado este, solo una mezcla con un secreto público (la metáfora de los colorines en http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange es cojonuda para entenderlo).

SSL usa DH al principio de la comunicación, pero nada más que para establecer un secreto común que se usará después como clave en comunicación mediante clave simétrica.

Esto lo hacen para establecer una clave simétrica, porque que es mucho más barata para encriptar/desencriptar computacionalmente que la criptografía de clave asimétrica. Sin embargo hay que autenticarse después igualmente (los secretos aleatorios no dicen nada de los extremos de la comunicación) así que este protocolo de key-agreement solo ayuda a establecer esta comunicación simétrica (sin que ningún observador pueda tener información sobre el secreto común).


Aún así sigues abierto a un man-in-the-middle como el que comento en #6. ¿Cómo sabes que has hecho el intercambio del secreto con Servidor y no con Oponente? Con certificados, sí o sí.

Oponente puede autentificarse con Diffie-Hellman con Servidor y Usuario y simplemente actuar de proxy (espiando/modificando las comunicaciones de paso) entre ambos.

Mírate la parte de las vulnerabilidades en http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange


Además es que para implementar un SSL half-baked, mejor usar SSL :P

1 respuesta
wineMan

-

PiradoIV

¡Muchísimas gracias cracks! :)

#12 En cualquier caso y a parte del SSL, en un servicio REST (al no tener estado ni guardarse la sesión), tendría que tirar algún sistema (como HMAC, token o lo que sea) para seguir haciendo las peticiones, aunque se sigan enviando por SSL, ¿no?

1 respuesta
LOc0

#14 No te compliques, en serio.

SSL + API-KEY

Te garantiza confidencialidad y además está protegido contra replay (capturar la petición cifrada y reenviarla).

Salu2 ;)

1 respuesta
PiradoIV

#15 Entonces

1.- Al registrar un usuario, generar un APIKEY aleatorio
2.- El usuario pide el APIKEY mediante la API usando su usuario y contraseña
3.- El resto de peticiones las puede hacer con su APIKEY

Todos los pasos a través de SSL.

3 respuestas
JuAn4k4

#6 Editado: esto me pasa por no leer hasta el final.

LOc0

#16 Las API-KEYS se suelen generar, guardarse en el server y enviarse al email del usuario.

Enviarle la API-KEY al usuario al principio cada vez no tiene mucho sentido porque precisamente el API-KEY es una manera de autenticar al usuario sin ncesidad de user+pass

Salu2 ;)

1 1 respuesta
elkaoD

#16 yo añadiría a lo de #18 que el usuario pueda regenerar la API key (por si se la roban).

PiradoIV

La idea es que una aplicación móvil, escritorio o lo que sea no tenga que guardar el usuario y contraseña localmente, pero tampoco obligar al usuario a copiar y pegar una API key. Además, de esta manera podría hacer que las keys expirasen cada cierto tiempo y que sean las apps consumidoras del servicio las que tengan que refrescarlas, no el usuario.

No es que pretenda desarrollar un búnker de datos súper secretos y críticos, pero enviar la API key por email no me parece seguro (no todo el mundo se conecta con SSL a su correo).

No sabía que la comunicación por SSL por sí misma fuese lo suficientemente segura como para no tener que implementar nada más, es más, todavía no estoy convencido del todo de usar simplemente un API key xD

Mil gracias de nuevo =)

Ninja-edit: Mientras tanto en YouTube...

2 respuestas
elkaoD

#20

La idea es que una aplicación móvil, escritorio o lo que sea no tenga que guardar el usuario y contraseña localmente, pero tampoco obligar al usuario a copiar y pegar una API key.

No te queda otra. Si no quieres user/pass necesitas autenticar de otra forma. ¿Igual poner una sola vez el usuario/pass y que la propia app sea la que coja la API key para subsiguientes conexiones?

Además, de esta manera podría hacer que las keys expirasen cada cierto tiempo que sean las apps consumidoras del servicio las que tengan que refrescarlas, no el usuario.

Hmmm, entonces un atacante podría refrescarla y joder al usuario. Yo lo dejaría en manos del usuario la regeneración periódica. Mientras que el usuario no tenga un virus (o le entren en el panel de admin o algo así) esa API key va a ser secreta.

"No es que pretenda desarrollar un búnker de datos súper secretos y críticos, pero enviar la API key por email no me parece seguro (no todo el mundo se conecta con SSL a su correo)."

Envía un link a tu interfaz web HTTPS. Deberías tener una panel de admin de las API keys donde ver la API key y regenerarla. Como es HTTPS siempre será seguro.

"No sabía que la comunicación por SSL por sí misma fuese lo suficientemente segura como para no tener que implementar nada más"

Yo siempre pienso en SSL como en un marco de trabajo de seguridad. SSL te ofrece con un 100% de garantías tres cosas:

  1. Confidencialidad: internet funciona como Usuario -> A -> B -> C -> D -> Servidor (y viceversa). Con SSL se garantiza que sólo Usuario y Servidor pueden ver los datos por mucha gente (incluso gente maligna) que haya enmedio.
  2. Integridad: de nuevo, ni A, B, C, D... podrán modificar los datos transmitidos.
  3. Autenticación: Gracias al certificado Usuario sabrá que está hablando exclusivamente con Servidor y no con otro.

¡Ojo! La 3 no va a la inversa, Servidor no sabe con quién cojones habla, de ahí que sea necesario login por user/pass o API key para que el usuario se autentique.

2 1 respuesta
B

Llego tarde, iba a decir lo de #21 , cuando quieres una comunicación segura quieres confidencialidad, integridad y autenticación. Y a veces más, por eso es necesaria muchas veces una third party.

Y si añades posibles errores en el canal hay más cosas.

También puedes probar sistemas de autenticación aleatoria si te da palo lo de los certificados, pero es complicarse. No sé si digo tonterías, hace un año que di la asignatura y no le presté mucha atención xD.

Por cierto, ahora no sé si meto la pata, pero IPSEC no te podría servir?

MTX_Anubis

#20 Si no quieres que el usuario la copie del mail, puedes hacer que el login de tu aplicación devuelva el api key y lo guardas. Diría que la mayoría de las apps funcionan así y las que yo he implementado han sido así también vaya.

OleMoudi

KISS -> #16

Si te quieres ahorrar el certificado SSL puedes implementar tú la capa de cifrado a nivel de aplicación en vez de usar TLS, pero como ya han comentado necesitas antes intercambiar con el usuario de manera segura algún tipo de secreto (apikey). Puedes mandarla por correo y asumir el riesgo de que este no use SSL o directamente asumir como única ventana posible de ataque el momento en el que el usuario se registra o cuando renueva el secreto.

Dependiendo de lo pobre que seas pueden ser riesgos asumibles o no :)

Haced caso a #6 que sabe del tema.

1 respuesta
Zeroner

Usar SSL es seguridad a la hora de que nadie pueda ver el tráfico. Pero no lo es si lo que pretendes es "ofuscar" como funciona tu API...

1 respuesta
PiradoIV

#24 ;***** muy agradecido, pagar por el SSL compensa con creces toda la parafernalia que habría que montar de otra manera.

#25 No quiero ocultar cómo funciona mi API, quiero que sea segura (y ya se ha comentado que ocultar no es seguridad).

Usuarios habituales