A día de hoy, una de las aplicaciones de
Software Libre de mensajería instantánea
(IM) disponibles en el mercado para su uso a nivel empresa o particular, por robustez, por funcionalidades y por ser una solución multi-dispositivo, podría ser el popular
Rocket.chat. En este artículo vamos a ver cómo se rompe la arquitectura de seguridad y se puede acceder a los datos enviamos en los mensajes por culpa de un fallo de seguridad que hay que corregir.
Figura 1: Cómo romper la arquitectura de cifrado de
mensajes extremo a extremo de Rocket.Chat [1 de 2]
Rocket.chat permite varias modalidades de uso de cara a una compañía, pudiendo montar un servidor centralizado
OnPremise, tu propio servidor
OnCloud, o simplemente mediante, el uso del servidor público que proporciona la propia compañía
Open.rocket.chat. La conexión al servidor puede realizarse desde múltiples dispositivos como se puede ver en la imagen anterior, tiene cliente Web, aplicación de escritorio para Windows/Linux/MacOS y app móvil para Android e iOS.
Figura 2: Arquitectura de conexiones multi-cliente para Rocket.chat
La funcionalidad a revisar en el artículo, será la del cifrado
Extremo a Extremo o
"End-2-End" (E2E). Dicha funcionalidad, implementa una capa de seguridad adicional al cifrado
TLS a nivel de red utilizado de forma común mediante el protocolo
HTTPS, en la mayoría de las comunicaciones actualmente. Como veremos al final, se podrá hacer un descifrado de los mensajes, y veremos cómo se puede mejorar la arquitectura de cifrado. Para entender mejor toda la arquitectura de cifrado, tienes el libro de
Cifrado de las comunicaciones digitales: de la cifra clásica a RSA 2ª Edición de 0xWord
El cifrado
E2E, por defecto, tiene la capacidad de hacer llegar un dato de forma segura desde un origen a un destino, de un modo descentralizado. En este caso, y dado que se encuentra en una arquitectura centralizada debido al diseño del producto, todos los mensajes enviados desde un origen pasarán y se almacenarán en el servidor central antes de llegar al destinatario, siendo la funcionalidad
E2EE (
End 2 End Encryption) la encargada de realizar este proceso de forma segura.
Arquitectura de Rocket.Chat
Para implementar esta función,
Rocket.Chat cuenta con un diseño de arquitectura
E2E del cual se ha realizado un pequeño estudio, para preparar este artículo. Esta arquitectura utiliza operaciones criptográficas de varios tipos, diferenciadas por su naturaleza matemática en simétrica, asimétrica y operaciones de hashing:
- Criptografía Simétrica: algoritmo utilizado AES, origen y destino comparten una clave de cifrado.
- Criptografía Asimétrica: algoritmo utilizado RSA, mediante el uso de un par de claves Publica y Privada, los datos serán cifrados con la clave pública y descifrados con la la clave privada.
- Hashing: algoritmo utilizado PBKDf2, la función derivación matemática que generará un resultado irreversible del cual no se puede obtener los datos originales de entrada.
La dirección de la implementación actual del producto a nivel arquitectura de software, por diferentes motivos, como el diseño de las funcionalidades de negocio y mantenimiento de una sola linea de código para los diferentes dispositivos, se implementa con el framework react-native.
Dicho
framework trabaja con
JavascriptCore que ademas de ejecutarse en los navegadores web, permite la posibilidad de integración de librerías implementadas en otros lenguajes de programación, como puedan ser
Java para sistemas operativos
Android u
Objetive-C para sistemas operativos
iOS:
Figura 5: Arquitectura de JavascriptCore con Java y Objetive-C
Las conexiones que se implementan entre los diferentes clientes y el servidor central de
Rocket.Chat podrán ser de dos tipos diferenciados por la dirección en la que se comunican:
Figura 6: Conexiones API REST y WebSocket
La conexión vía API Rest es Cliente → Servidor y unidireccional, mientras que la conexión vía Websocket permite en modo full-duplex transferencias bi-direccionales Servidor → Cliente y Cliente → Servidor.
Descripción de la arquitectura E2E
La funcionalidad
E2E, se arranca tras la autenticación inicial de un usuario (
U) sobre sobre un dispositivo (
D).
- El dispositivo (D), solicitará al usuario (U) o generará unas credenciales específicas E2E (En función de si es la primera vez o no, que el usuario se autentica en el dispositivo con el servidor de Rocket.Chat).
- Tras introducir las credenciales mediante la derivación de la contraseña junto al identificador unívoco del usuario (U) UID y el uso del algoritmo criptográfico de hashing PBKDF2, se generará la primera clave criptográfica de la aplicación master-key.
Figura 7: Generación de Master Key en dispositivo
A continuación, el dispositivo (
D) como cliente del servidor de
Rocket.Chat procederá con la generación o solicitud (en función de si es la primera vez en la que el usuario se autentica en el dispositivo) de un par de claves
RSA de longitud
2048 que serán las claves criptográficas
E2E del usuario:
- Generación public_key, private_key: RSA-OAEP 2048
- Utilizando la master-key, mediante criptografía simétrica utilizando el algoritmo AES-CBC el dispositivo (D), cifrará la private_key.
Figura 8: Generación de claves pública y privada para cifrado asimétrico
El dispositivo (
D), mediante una llamada a la
API Rest de tipo
POST, sobre la
API de
Rocket.Chat realiza el envío del par de claves,
public_key y
private_key (ésta última cifrada, para garantizar la confidencialidad del usuario).
- La función de la API Rest que proporciona este servicio, es e2e.setUserPublicAndPrivateKeys.
- El servidor de Rocket.Chat en su BD no relacional (mongodb) almacenará estas claves asociadas al usuario (U), en la colección users.
Figura 9: Envío de claves pública y privada a servidor de Rocket.Chat
La aplicación para cifrar los datos punto a punto, requiere de una habitación o chat seguro por tanto ya sea dirigido desde el usuario (
U), al usuario unívoco (
U₁) o a los múltiples usuarios (
U₁),(
U₂)...(
U_n), por lo tanto será necesario crear un grupo cifrado.
- La operación de la API Rest del servidor de Rocket.Chat que proporciona este servicio será create.group, especificando los parámetros adecuados de grupo privado y encriptado.
- El servidor de Rocket.Chat generará en la BD no relacional una entrada en la tabla rocketchat_subscriptions por cada usuario (U1..n), que pertenezca a la habitación segura alojada en la colección rocketchat_room.
Figura 10: Creación de un grupo de cifrado con clave simétrica
El creador del grupo seguro, será el encargado de generar la clave criptográfica de cifrado de mensajes
Room-Key (el cual será cifrado simétrico), y almacenarlo únicamente de forma cifrada en la
BD del servidor, en la colección
rocketchat_subscriptions, mediante la operación de la
API Rest e2e.UpdateGroupKey. Éste proceso se realizará
N veces para cada uno de los usuarios que pertenecen al grupo:
- Se cifrará la Room-Key: de forma asimétrica mediante el algoritmo RSA para cada usuario del chat seguro.
- Se utilizará para el cifrado la public_key, disponible en la colección users del servidor, reportada mediante la invocación al servicio API Rest de Rocket.Chat e2e.requestSubscriptionsKeys.
Figura 11: Envío de claves Room-Key a los usuarios del grupo
Para la obtención de la clave de cifrado de mensajes
E2E, en determinado grupo cualquier usuario que sea miembro de este, deberá realizar los siguientes pasos:
- El usuario (U), ya autenticado en la aplicación y en la arquitectura E2E estando en posesión de su master-key.
- Solicitará la clave de sesión E2EKey, almacenada para su usuario (U), en la colección rocketchat_subscription (cifrada asimétricamente con RSA).
- Solicitara sus claves de cifrado al servidor, public_key y private_key (esta última, cifrada simétricamente con AES).
- Descifrará con AES, la clave privada mediante el uso de la master-key.
- Descifrará con RSA, utilizando la clave privada (private_key) descifrada y la clave E2E (E2EKey) obteniendo la room-key o session-key.
Saludo,