Kong Gateway permite el uso del mecanismo de autenticación HMAC (Hash-Based Message Authentication), que a diferencia de otros mecanismos como la autenticación básica o por API Key, evita el envío de contraseñas en texto claro en la petición y también evita el replay, al apoyarse en la firma digital (Hash) de los encabezados de la petición HTTP, resultando más seguro y apropiado para su uso en Clientes Confidenciales (aquellos que son capaces de almacenar una contraseña con seguridad, como sería el Backend de una aplicación, una Web con Server-Side Rendering, etc). En este Post os explico en que consiste el mecanismo de autenticación HMAC y cómo configurarlo en Kong utilizando Konga.
Continuando con la serie de Posts acerca de Kong, en esta ocasión os voy a explicar el mecanismo de autenticación HMAC (Hash-Based Message Authentication) para seguidamente ver cómo configurarlo en Kong utilizando Konga, y finalmente probarlo con un curl, viendo la forma de construir la firma digital y el encabezado Authorization necesario, y probando la ejecución de replays.
Si quieres seguir este Post paso a paso, te recomiendo que te apoyes en el Docker Compose que compartí en GitHub (GitHub – ElWillieES – kong-docker-lab), y que sigas los anteriores Post (Introducción a Kong Gateway y Kong Dashboard y Consumidores, Autenticación, y Autorización de APIs en Kong – I) en los que configuramos la publicación de varios Servicios (APIs) en Kong así como la configuración de autenticación básica (Basic Auth) y de clave (Key Auth) con ACLs, que utilizaré como punto de partida para los ejemplos que voy a realizar en este nuevo Post.
Qué es la autenticación HMAC (Hash-Based Message Authentication)?
En el Post anterior vimos cómo utilizar la autenteción básica (Basic Auth) y por clave (Key Auth) en Kong. Estos tipos de autenticación son aún muy habituales, especialmente para su uso en Clientes Públicos (aquellos que no son capaces de almacenar una contraseña con seguridad, como sería Native Apps, JavaScript Apps – SPAs, etc), pero a su vez son muy vulnerables (y ya se han quedado un poco antiguos, aunque se siguen usando), debido a que:
- El secreto (API Key o el usuario y contraseña) viaja en texto claro en la petición HTTP, lo que facilita que pueda ser obtenido por un usuario malicioso que ambicione obtener acceso a nuestros datos.
- Las peticiones son repetibles (replay), es decir, una misma petición se puede ejecutar una y otra vez, ya sea con el fin de hacer un ataque de denegación de servicio, obtener el dato actualizado sucesivas veces a lo largo del tiempo, si quisieran hacer Web Scrapping para obtener todos los datos de nuestra base de datos, o por cualquier otro oscuro motivo.
La autenticación HMAC (Hash-Based Message Authentication) intenta impedir estas vulnerabilidades utilizando algoritmos de firma digital junto con una clave secreta compartida, siendo apropiado para su uso en Clientes Confidenciales (aquellos que son capaces de almacenar una contraseña con seguridad, como sería el Backend de una aplicación, una Web con Server-Side Rendering, etc), de tal modo que:
- Se utiliza una clave secreta compartida, es decir, conocida por el cliente que realiza la petición y el servidor que la recibe. Nadie más la conoce.
- El secreto (la clave secreta compartida) no viaja en la petición HTTP, en su lugar, viajan los datos de la propia petición junto con una firma digital de los mismos (Hash) y el nombre del usuario, de tal modo, que el servidor es capaz de comprobar que los datos no han sido modificados en tránsito además de poder autenticar al usuario.
- Evita las peticiones repetibles (replay), ya que la firma digital se realiza entre otros sobre un encabezado con la fecha y hora, y el servidor sólo permitirá peticiones con un valor de fecha y hora actual. Por lo tanto:
- Si alguien intenta cambiar el valor del encabezado de fecha y hora, deberá volver a generar la firma, por lo que si no tiene la clave secreta, no podrá realizarlo, y la petición no se considerará como válida.
- Si no cambia el valor del encabezado de fecha y hora, podrá utilizarlo sólo durante unos minutos, en función del valor de la configuración clock skew, que veremos más abajo.
- Permite especificar qué encabezados de la petición (request headers) deben ser incluidos en el cálculo de la firma digital (Hash), para mayor seguridad. Por defecto, se incluye un encabezado Date que inclue la fecha y hora. Pero además, podríamos forzar que se incluyera un encabezado con Dirección IP de origen, o cualquier otro encabezado, que al ser incluido en la firma digital, tendremos la seguridad que no ha sido alterado en tránsito.
- Utiliza un encabezado adicional (Authorization) en las peticiones HTTP, en el que se especifica el usuario, el algoritmo utilizado para generar la firma digital (ej: HMAC-SHA256), qué encabezados y en qué orden se han utilizado para generar la firma digital, y la propia firma digital en formato Base64.
De este modo, con HMAC conseguimos un punto extra de seguridad frente a otros tipos de autenticación como Basic Auth ó Key Auth, de una forma muy sencilla (ej: sin necesidad de servidores de identidad), que funciona bien con Clientes Confidenciales.
Veamos un ejemplo.
Si queremos hacer una petición GET el 4 Marzo del 2023 a las 10:14:00, a un servicio que hemos publicado en Kong en la ruta /service-c utilizando HTTP/1.1, utilizando autenticación HMAC con SHA256, autenticándonos como el usuario willie, y deseamos incluir en la firma un encabezado adicional dummy (en la práctica, podemos no incluirlo, o incluir otros que nos interesen más) así como el request-line (este lo podemos ver ejecutando un curl -vsi), deberemos primero obtener el valor de la firma digital de los encabezados date, dummy, y request-line (podemos utilizar cualquier Web gratuita para ello) utilizando la clave del usuario.
Con esto, ahora podemos construir el encabezado Authorization, especificando que queremos usar HMAC, el usuario (ej: willie), el algoritmo utilizado para generar la firma digital (ej: hmac-sha256), qué encabezados y en qué orden se han utilizado para generar la firma digital, y la propia firma digital en formato Base64. Para este ejemplo, sería:
Authorization: hmac username="willie",algorithm="hmac-sha256",headers="date dummy request-line",signature="ysQs2zf9BUqTASUscia3vvWqIKfRfPLCFQ2XQg2AwDI="
Y así podríamos construir nuestra petición HTTP, que si fuera con un comando curl, podría ser un comando como el siguiente:
curl -i --location 'http://localhost:8000/service-c' \
--header 'date: Sat, 04 Mar 2023 10:27:00 GMT' \
--header 'dummy: kong' \
--header 'Authorization: hmac username="willie",algorithm="hmac-sha256",headers="date dummy request-line",signature="ysQs2zf9BUqTASUscia3vvWqIKfRfPLCFQ2XQg2AwDI="'
No es tan inmediato como la autenticación básica o por API-Key, pero es mucho más seguro, y bastante fácil de implementar. Mucho más, si además usamos Kong, y nos ahorramos implementarlo en cada una de nuestras APIs, al delegarlo en el API Manager.
Configuración de Autenticación HMAC en Kong usando Konga
En esta ocasión queremos mantener varios tipos de autenticación, la autenticación básica (Basic Auth) a nivel Global, la de clave (Key Auth) a nivel de una ruta de un servicio con ACLs, y la HMAC (HMAC Auth) a nivel de otro servicio, de tal modo que puedan convivir todos estos métodos de autenticación aplicando cada uno sólo en los casos correctos, pudiendo haber usuarios que utilicen Basic Auth, API Key, o HMAC, indistintamente, en función del Endpoint y del propio usuario. Esto requiere alguna configuración especial, como se describe en la documentación de Kong (Kong Gateway – Allowing Multiple Authentication Methods), y como ya vimos y realizamos en el Post anterior (Consumidores, Autenticación, y Autorización de APIs en Kong – I).
Dicho esto, empezamos. Lo primero que vamos a hacer es habilitar la Autenticación HMAC en Kong, como mecanismo de autenticación para todas las APIs del Servicio C, por lo tanto, necesitamos habilitar el Plugin de HMAC Auth a nivel de dicho Servicio. Para más información acerca del Plugin de HMAC Auth: Kong – Plugin – HMAC Auth
Vamos a hacerlo a través de Konga. Para ello en la sección Services, entramos en el Servicio service-c, y en la pestaña de Plugins, click en Add Plugin.
Podemos elegir entre varios Plugins de Autenticación, en nuestro caso nos interesa el de HMAC Auth. Click en Add plugin para continuar.
La siguiente pantalla es importante, ya que podemos configurar varias cosas, en particuar nos interesa:
- El valor de clock skew (la recomendación es 300), tendiendo en cuenta que aumentarlo nos hace más vulnerables a replay-attacks.
- Configurar el ID del usuario anónimo (para que haga fallback y convivan múltiples mecanismos de autenticación en Kong).
- Especificar qué encabezados queremos que sean obligatorios en las peticiones entrante (request headers), lo cual puede ser útil, ya que podemos requerir encabezados con valores que nos puedan resultar de interés (ej: dirección IP de origen), utilizándolos en la generación de la firma digital, y así tener seguridad de que no han sido alterados en tránsito. Por defecto se incluye el encabezado Date.
- Especificar el ó los algoritmos que deseamos utilizar para obtener la firma digital o Hash (se puede elegir entre varios, desde hmac-sha1 hasta hmac-sha512) en nuestro caso elegimos únicamente hmac-sha256, aunque es posible incluir varios.
Click Add Pluign para continuar.
Seguidamente, crearemos unas credenciales HMAC para un consumidor que usaremos para probar esta configuración. Recordemos que un Consumidor no tiene necesariamente que ser un Usuario, es decir, por ejemplo, un Consumidor podría ser una empresa (ej: un Cliente o un Proveedor) en la que creamos varias credenciales, para los diferentes usuarios y aplicaciones que consumen nuestras APIs desde dicha compañía. Incluso para una empresa, podríamos crear diferentes Consumidores con roles diferentes, y darle a cada Consumidor acceso sólo a las APIs que necesita.
En nuestro caso utilizaremos el consumidor willie que ya creamos anteriormente. Para ello, en la sección Consumers seleccionaremos el consumidor willie, en la página Credentials, iremos a la pestaña HMAC, click en Create credentials, especiamos un usuario y contraseña, y click Submit.
Con esto, ya estaría todo configurado.
Probando la autenticación HMAC
Vamos a probarlo. Para poder hacer una prueba debemos construir el valor que irá en el encabezado Authorization, para lo cual primero necesitamos obtener la firma digital (Hash) en formato Base64, que tenemos que incluir en dicho encabezado.
En nuestro caso, vamos a firmar digitalmente el valor de los encabezados, dummy, y request-line. Para nuestra prueba, podemos obtener el valor de la firma digital de estos encabezados (con sus valores) utilizando cualquier Web gratuita para calcular HMAC con SHA265 (hay un montón), como se muestra en el siguiente ejemplo con los valores para la primera llamada:
Con esto ya podemos obtener el valor de los diferentes encabezados de nuestra petición, incluido el encabezado de Authorization, que serían los siguientes. En el encabezado Authorization, especificaremos cuál es nuestro usuario (ej: willie), qué algoritmo se ha utilizado para obtener la firma o Hash (ej: SHA256), qué encabezados y en qué orden se han utilizado para obtener la firma (date, dummy, y request-line), y finalmente la propia firma o Hash.
date: Sat, 04 Mar 2023 10:14:00 GMT
dummy: kong
Authorization: hmac username="willie",algorithm="hmac-sha256",headers="date dummy request-line",signature="YYFjcENVCHZqy7SnLoHqVqYOqRRCsaBqeVYhq4k5JKM="
Por seguridad, es importante incluir un encabezado con la fecha/hora y el request-line para obtener la firma. Así nos podemos proteger frente a situaciones en las que intenten utilizar la misma firma sucesivas veces en el tiempo (replay) o contra diferentes URL. Poder protegernos de estas cosas, y que no viajen las credenciales en claro, son las ventajas de utilizar HMAC.
A continuación se muestra como conseguimos acceder con éxito al Servicio C (que publicamos en Kong con nuestro Dockerfile) utilizando HMAC con el encabezado Authorization, vemos como no podemos acceder si no usamos ningún tipo de autenticación (obtenemos un 401), y finalmente vemos como podemos acceder con autenticación básica (permitida a nivel global en Kong, mientras que HMAC está sólo a nivel del Servicio C).
Si seguidamente hacemos un «replay» de la petición que utiliza autenticación HMAC, es decir, volvemos a enviar la misma petición a Kong con los mismos datos y firma SHA, seguirá funcionando (igual que ocurría con Basic Auth y con API Key), sin embargo, pasados unos minutos, si hacemos un «replay» de nuevo, ya no funcionará, siendo necesario construir una nueva petición con la fecha y generando una nueva firma, para que Kong nos permita el acceso, lo que proporciona mucha más seguridad que la autenticación básica o por clave, ya que la contraseña no viaja y además estamos protegidos de replays.
A continuación lo podemos ver con un ejemplo, como un replay varios minutos después acaba en un 401, mientras que al construir de nuevo la petición y firma con la fecha y hora actualizada, podemos acceder a nuestra API con éxito (200) de nuevo.
Despedida y Cierre
Hasta aquí llega este Post, como continuación a los anteriores Posts Introducción a Kong Gateway y Konga Dashboard y Consumidores, Autenticación, y Autorización de APIs en Kong – I, utilizando el Docker Compose compartido en GitHub para quienes deseen seguir este laboratorio paso a paso: GitHub – ElWillieES – kong-docker-lab
El objetivo de este Post era doble:
- Por un lado, explicar la autenticación HMAC (Hash-Based Message Authentication) como una alternativa más segura que la Autenticación Básica o por API Key (no viaja la contraseña en claro y evita el replay), para su uso en Clientes Confidenciales (aquellos que son capaces de almacenar una contraseña con seguridad, como sería el Backend de una aplicación, una Web con Server-Side Rendering, etc), aunque la Auntenticación Básica y por API Key siguen siendo mecanismos muy utilizados.
- Además hemos visto con un ejemplo cómo configurar la autenticación HMAC en Kong utilizando Konga, manteniendo también de forma simultánea la autenticación básica, y cómo probarlo con un comando curl, obteniendo la firma digital y construyendo el encabezado Authorization, probando a hacer un replay, etc.
Poco más por hoy, como siempre confío que la lectura resulte de interés.