
Cifrado Aleatorio de Datos
Explicando un antiguo proyecto que aun sigue activo.
SEGURIDADPROYECTOSARQUITECTURADESARROLLOCRIPTOGRAFIA
JLJuarez
6/24/20257 min read
Para comprender este título tan rimbombante, debo informaros que lo que os voy a explicar forma parte de una solución que diseñé e implementé para un cliente muy conocido hace muchos años y que, a día de hoy, sigue utilizando para cierto tipo de comunicaciones. Estas no pueden depender de que la VPN o el TLS de turno no estén comprometidos de alguna forma; es decir, que no exista algún elemento intermedio leyendo el tráfico en claro.
Si bien generalmente podemos garantizar la integridad de los datos dentro de nuestro perímetro de seguridad, la necesidad de desplegar componentes en el CPD de otro actor expande nuestra superficie de ataque. Esto significa que perdemos el control directo sobre dichos componentes y sus interacciones con el entorno de destino, lo que introduce posibles vulnerabilidades y, por tanto, aumenta el riesgo de exfiltración de datos.
Teniendo en cuenta el supuesto comentado, intentaremos darle solución haciendo uso del cifrado previo de los datos mediante claves configuradas en el proceso de despliegue (enrollment). Con ello, lo que pretendemos es complicarle la vida al atacante, impidiendo en la medida de lo posible que disponga de acceso a los datos que enviamos o recibimos en nuestra comunicación. Para esto es necesario cumplir con las siguientes premisas:
Estas claves se deben obtener/distribuir a través de un canal diferente al utilizado en la comunicación objeto.
Deben ser almacenadas de forma segura; esto es, de forma que estén protegidas de accesos no autorizados.
Está claro que si no podemos garantizar estos puntos, no merece la pena ni siquiera que nos planteemos un montaje de este tipo y será mejor buscar soluciones de otro tipo.
Entrando en materia
Comencemos con un ejemplo sencillo: imaginemos un paquete con una estructura de datos. Si ciframos los datos que almacena o incluso la estructura completa (todo dependerá de las necesidades de cada uno), un atacante que tenga acceso a la comunicación no podrá leer los datos transmitidos si no dispone de la clave utilizada.
Hasta aquí podríamos decir que hemos solucionado el problema, ya que hemos cumplido el objetivo. Pero los atacantes son muy listos. Si, por casualidad, utilizamos la misma clave para todos los componentes y, además, el atacante tiene suficientes medios a su alcance, podría conseguir acceso a la clave o incluso utilizar algún sistema de análisis de patrones y adivinarla si esta no es suficientemente fuerte, quedando así todo el sistema comprometido.
Pero ahora imaginemos un sistema en el que se usan múltiples claves de cifrado y que estas están disponibles de forma segura tanto para el emisor como para el receptor. Además, sumemos la posibilidad de que en cada comunicación y de forma aleatoria, el emisor selecciona una clave de entre las disponibles, cifra el mensaje y, en el paquete de envío, adjunta el identificador de la clave que ha utilizado. Cuando el mensaje le llegue al receptor, este recuperará el identificador de la clave utilizada y podrá usarla para descifrar el mensaje, más o menos como el ejemplo de la imagen.
Esto no es un invento mío; se lleva utilizando desde hace muchos años en sistemas de comunicaciones seguros. Uno que posiblemente conozcáis es el famoso JWT, el cual tiene dos especificaciones relacionadas que explican el uso de claves compartidas de forma segura para implementar el firmado (JWK) y el cifrado de los mensajes (JWE).






Cuestión de claves
Ahora bien, llegados a este punto podemos trabajar con dos planteamientos posibles:
Claves simétricas (claves compartidas): una misma clave para el cifrado y descifrado; más sencillo de implementar y gestionar, pero limitado al cifrado/descifrado y posible firma.


Claves asimétricas (claves pública y privada): cada sistema que interviene en la comunicación dispone de un par de claves (Pub/Priv) y compartirá su clave pública con los sistemas con los que necesite comunicarse; más complicado de implementar y gestionar, pero además permite identificar de forma única al emisor de los datos.


Cuál de los dos sea el idóneo dependerá de las necesidades de cada uno. Eso sí, debemos tener en cuenta que, según el tipo usado, la complejidad de implementación y gestión podrá ser mayor o menor. Por ejemplo, así más o menos quedaría un sistema formado por cuatro microservicios utilizando una clave común.


No voy a entrar en muchos detalles, pero como veis, cada microservicio implementa un conjunto de elementos intermedios encargados de cifrar, descifrar y custodiar las claves de forma segura. Por supuesto, el HSM no tiene por qué ser físico; incluso podría ser un agente que se comunique con un "cluster HSM" centralizado.
Pero no nos quedemos ahí, porque podemos complicarlo algo más. ¿Y si en cualquiera de los dos planteamientos anteriores, en vez de usar un solo juego de claves, usamos más de uno? Lógicamente, cuantas más claves haya en juego, más complicado les resulta a los atacantes adivinarlas. ¿Y si además usamos un proceso aleatorio para elegir la clave de cifrado? En el caso de que el atacante encuentre una de las claves, no podrá descifrar el siguiente mensaje si la clave es diferente. Más o menos, utilizando el ejemplo anterior, quedaría así:


En cada comunicación se puede utilizar una clave diferente, por lo que, en caso de que el atacante encuentre una, solo se compromete una mínima parte del sistema, pudiendo resolver el problema casi de inmediato.
Hasta aquí creo que todos tenemos claro que, aumentando el número de claves, reforzamos la integridad de los datos y si, además, la elección de estas es aleatoria, estaremos ante un sistema algo más complicado de romper. Si ya cumplimos las reglas básicas de complejidad de clave y custodia adecuada, estaremos ante un sistema que muy pocos conseguirán romper, que es de lo que se trata.
Sí, ya sé que lo que planteo se parece al clásico PowerPoint que todo lo aguanta y que posiblemente tenga algunos agujeros, que complica la comunicación y aumenta las necesidades de proceso. Pero si en nuestro negocio la prioridad es la protección de los datos en trayecto, independientemente de que exista o no un canal previo que sea seguro y nuestro presupuesto es reducido, este puede resultar un proceso muy efectivo a la par que económico de implantar.
La implementación
Bueno, en este punto ya nos encontramos con lo complicado, pero no os creáis que os voy a poner aquí una guía paso a paso, no, señor. Aquí la idea es que cada uno implemente esta solución con la tecnología y elementos que le resulten más familiares.
Empecemos por el principio: tanto si utilizamos cifrado simétrico como asimétrico, necesitaremos un repositorio donde almacenar las claves. Por supuesto, lo mejor sería contar con un HSM, pero dependiendo de nuestro presupuesto y medios disponibles, podemos usar otro tipo de almacén que cumpla con nuestro propósito. Lo importante es que, como mínimo, garanticemos los siguientes puntos:
Acceso controlado: En el caso de que sea compartido, solo quien está autorizado puede acceder al almacén.
Utilizar una clave de acceso: En el caso de que alguien no autorizado disponga de acceso, que no pueda recuperar las claves almacenadas sin la clave maestra.
Por otro lado, necesitaremos construir o refactorizar nuestros componentes para que sigan el esquema planteado en los ejemplos, esto es:
Exponer un controlador/Endpoint API que implemente la lógica necesaria para recibir el mensaje cifrado y contestar adecuadamente con otro mensaje cifrado; es decir, que se encargue del Request/Response.
Disponer de un módulo de descifrado con la lógica necesaria para identificar la clave a usar y tratar con el HSM o almacén de claves para descifrar el mensaje, que deberá trasladar al componente core.
De la misma forma, necesitaremos un módulo de cifrado que se comunique con el HSM o almacén de claves y elija una clave aleatoriamente para cifrar los mensajes que le entregue el core.
Como requisito final, el core solo debería implementar una interfaz para comunicarse con el módulo de cifrado y otra para el descifrado; el resto de elementos y cómo se construyan/implementen será cosa de cada uno.
Como veis, en términos generales, es una solución relativamente sencilla, ya que la complejidad subyace en la lógica de consumo de las claves y el tema del cifrado/descifrado de los datos. Pero no es nada que no se pueda solucionar con una buena librería criptográfica de las que hay disponibles y el uso adecuado del HSM o almacén de claves. Por otro lado, sí es cierto que requiere una buena planificación y análisis, pero eso es algo que ya deberíamos aplicar por defecto en todas nuestras soluciones.


La estructura del dato
Bien, como he indicado antes, necesitamos una estructura que nos permita transmitir nuestros datos cifrados junto al identificador de la clave de cifrado. Para solucionar esto último, podemos utilizar cualquier opción con la que nos sintamos cómodos; eso ya lo dejo a vuestra elección, aunque cuanto más sencillo sea todo, mejor. Básicamente, estaríamos hablando de algo similar al siguiente ejemplo:
Historias de un Tech Lead
Reflexiones sobre arquitectura, desarrollo de software y otras cosas.
© 2025. All rights reserved.
NOTA:
Si, ya lo se, casi todas las imágenes contenidas en este blog, han sido y posiblemente serán generadas por IA, por desgracia no dispongo de capacidades artísticas adecuadas y mucho menos de tiempo para buscar imágenes adecuadas en la red. Por lo que muy pocas serán creadas por mi directamente.