Hola, soy Luis y esta vez les traigo un nuevo post.
Si ha utilizado API, no es ajeno a oAuth2 y Refresh Tokens. Aunque hay numerosas formas de asegurar una API, oAuth2 siempre ha sido el Durex para API y oAuth2 nunca ha fallado a la API, bueno, casi el 98% del tiempo, si se usa correctamente.
oAuth2 es un marco muy versátil y reforzado que es invaluable cuando se trata de proteger y compartir recursos de forma segura. Sin embargo, durante uno de mis compromisos anteriores, me encontré con un escenario en el que no le fue muy bien. El objetivo es explorar la posibilidad de utilizar algo completamente diferente para resolver el problema. Permítanme llamar su atención sobre un escenario muy específico, que involucra a un vendedor de API y un revendedor de API, un modelo Hub & Spoke para ser precisos.
Desde la perspectiva de API Gateway B, API Gateway A es solo otra aplicación. Pero en realidad, API Gateway A es un revendedor de las API de API Gateway B. Ahora bien, esto tiene un significado. Debido a que Gateway B trata a Gateway A como una sola aplicación, Gateway A recibe un único conjunto de credenciales para consumir recursos en Gateway B. Esto crea una situación bastante única, que puede escalar a una condición de carrera si no se maneja correctamente.
Analicemos el escenario anterior, Gateway A, obtendría un token de acceso y un token de actualización de Gateway B y comenzaría a atender a sus clientes. Este token de acceso debe usarse para dar servicio a muchas aplicaciones de muchos clientes de Gateway A, a quienes están revendiendo las API de Gateway B. En cierto punto, el token de acceso caducaría y Gateway A tendría que iniciar el flujo de token de actualización. Durante este proceso, que puede tardar desde un par de milisegundos hasta un par de segundos, pueden suceder dos cosas.
- Todas las llamadas a API que requieran Gateway B fallarán
- Todas las llamadas de API que requieran Gateway B se pondrán en cola hasta que se actualice el token. Esta es una mejor opción dado que la actualización es rápida y la llamada a la API no se agota o, lo que es peor, no se convierte en SlowDDoS.
Puede ocurrir otro escenario si la situación no se maneja adecuadamente. Imagínese, si la actualización del token se realizó al azar por cada servicio en la puerta de enlace A que posteriormente requiere consumir un recurso en la puerta de enlace B, esto provocará una condición de carrera en la que cada servicio actualiza simultáneamente el token y, finalmente, terminará en un punto muerto.
Una posibilidad de eliminar este problema es usar un token con un TTL largo, pero este es un riesgo de seguridad masivo, por lo tanto, un gran NO. Otras opciones menos atractivas son utilizar la autenticación básica y proteger el canal de red mediante VPN o SSL mutuo. Pero siento que hay otra manera, así que escúchame.
Lo que propongo es distanciar socialmente el flujo de actualización simbólica, ya sabes, manteniéndome con el tema de la pandemia y todo. En lugar de utilizar un token de actualización que requiere que el cliente y el servidor se comuniquen, ¿por qué no hacerlo de forma independiente?
TOTP¹ ha estado en el negocio durante años, pero se ha utilizado principalmente en 2FA. ¿Qué pasa si podemos usarlo para reemplazar el flujo del token de actualización? Por algún milagro, si no sabe qué es un TOTP, el PIN que usa con Google Authenticator o el PIN que usa para iniciar sesión en Facebook, sí, eso. TOTP funciona sincronizando los relojes del cliente y el servidor y teniendo un secreto compartido y usando un algoritmo hash como HMAC.SHA512 para generar un código de un solo uso. Una vez que los relojes del sistema están sincronizados y los secretos se comparten, el cliente puede generar estos códigos sin hablar con el servidor.
Ahora veamos cómo funcionaría esto con nuestro problema original. La puerta de enlace A se iniciaría y se comunicaría con la puerta de enlace B, después de la autorización inicial, en lugar de un token de acceso y un token de actualización, la puerta de enlace A recibirá un secreto. Además, los relojes del sistema deberán estar sincronizados. La desventaja de este enfoque es que el servidor tendrá que mantener diferentes intervalos de tiempo junto con los detalles de la aplicación para contar los pasos de tiempo correctos para generar el TOTP en el lado del servidor. Después de este paso inicial, el cliente puede seguir generando TOTP sin hablar con el servidor.
Un TOTP funciona en una ventana de tiempo variable, un código es válido durante un período de tiempo determinado y el servidor también está configurado para tener en cuenta una pequeña discrepancia en el tiempo (para tener en cuenta cualquier latencia de red, etc.). Por lo tanto, incluso si diseña su solución para generar un TOTP para cada llamada a la API, dentro de una ventana de tiempo determinada, para un secreto determinado, el algoritmo hash dará el mismo TOTP. En el fragmento de código a continuación, el generador de TOTP está configurado para una ventana de tiempo de 30 segundos y, como puede ver, en 30 segundos, el valor de TOTP generado es el mismo. Por supuesto, también puede decidir invalidar el código después de un solo uso, quiero decir que se llama OTP y todo.
TimeProvider timeProvider = new SystemTimeProvider(); codeGenerator = new DefaultCodeGenerator(HashingAlgorithm.SHA512); DefaultCodeVerifier verifier = new DefaultCodeVerifier(codeGenerator, timeProvider); verifier.setTimePeriod(30); verifier.setAllowedTimePeriodDiscrepancy(1);
Enter Secret: P4V35TSCIVTYWZRZP44TUFFNHHNULFXD 997096 997096 979824 979824
Por lo tanto, incluso si dos aplicaciones generan TOTP simultáneamente, no resultará en un escenario de bloqueo. Donde, como cuando se usan tokens de actualización, si dos aplicaciones actualizan simultáneamente el mismo token, podría provocar un bloqueo. El otro beneficio de este enfoque es que se reducirá la cantidad de llamadas API que llegan a Gateway B, porque la actualización del token se realizará en el lado del cliente.
Ahora, para probar esto correctamente, pirateé rápidamente dos aplicaciones de arranque de primavera para imitar Gateway A y Gateway B, Gateway A tendrá un solo conjunto de credenciales de Gateway B y lo compartirá con tres aplicaciones en Gateway A y usando tres subprocesos concurrentes para acceder a los recursos en Gateway B. Puede encontrar el código fuente completo aquí³. Los resultados fueron prometedores.
Estos resultados se capturaron durante un período de 10 minutos con un tiempo de vencimiento del TOTP de 30 segundos. Tres aplicaciones lograron compartir el mismo secreto y aún así lograron actualizar y acceder a recursos en Gateway B sin encontrarse en una condición de carrera.
No voy a llegar tan lejos como para declarar que esta solución es perfecta, pero se muestra prometedora y resuelve un problema específico que enfrenté y que no pude resolver usando tokens de actualización. Y lo que es más importante, quería sacar la idea para poder iniciar una discusión, y si esta podría ser la chispa que enciende una llama que podría construir algo sólido y una verdadera solución, entonces me encantaría ser parte de la solución.
Gracias por leer.
Añadir comentario