Actualmente estamos diseñando una API REST y estamos pensando en protegerla.
Al revisar una gran cantidad de documentación, ha quedado claro que hay 2 opciones disponibles.
Autenticación HMAC
Al codificar con HMAC-sha1 una serie de elementos predefinidos con secret_key, firmamos la solicitud. La verificación se realiza haciendo exactamente el mismo lado del servidor de procesos y comparando los hashes resultantes.
Nuestra implementación es así:
- Obtener la marca de tiempo actual
- Creando HMAC:
hmac(full_url + request_body + timestamp + secret_key + token)
- Enviando la firma como:
clientId + hmac_signature + timestamp + token
La principal ventaja de esto, es que la clave secr_ nunca se transmite en la solicitud, lo que evita la mayoría de los ataques de reproducción. Pero como inconveniente, tenemos que almacenar las credenciales del cliente (secret_key) en un formato sin procesar en nuestra base de datos. Y si nuestra base de datos se ve comprometida, también podríamos revocar todas las credenciales de los clientes API actuales.
Autenticación HTTPS
El uso de SSL a través de nuestra API nos permitirá crear un canal seguro para intercambiar información privada.
Básicamente, enviamos la misma información sin modificarla con HMAC.
Nuestro diseño será exactamente igual (o muy similar a) la especificación OAuth2.
En comparación con HMAC, esto tiene muchas ventajas, ya que delegamos la mayor parte del trabajo a SSL. Y los clientes no tienen que incluir una biblioteca para el hashing como con HMAC. Finalmente, nuestra base de datos está segura ya que la clave secreta del cliente se almacenará de forma segura.
Pero si alguien logra con éxito una solicitud, podría robar la clave secreta y comenzar a crear sus propias solicitudes.
¿Hay alguna forma de utilizar las ventajas de HTTPS sin enviar credenciales claras y sin tener que almacenar credenciales claras?
Uno de nuestros diseños alternativos fue el uso del lado del cliente generado por la clave pública / privada, y se usa para intercambiar una clave para cifrar secret_key para futuras solicitudes. Pero no muchos navegadores tienen esta capacidad ( <keygen>
) y es una molestia para las aplicaciones móviles.