4dim / Notas
Los tokens de un canal van cifrados en la base
Un token de WhatsApp escribe a los clientes en nombre del negocio. Tres formas de que se escape sin que nadie ataque nada, y las cinco decisiones de cifrarlo bien: el modo, la llave, el error que nombra la variable y la versión que permite rotar.
Lo que puede hacer un token robado
Si guardas credenciales de otros servicios —un token de WhatsApp, una llave de pasarela de pagos— esta nota te dice por qué restringir el acceso a la base de datos no basta, y las cinco decisiones de cifrarlas bien.
Empieza por entender qué es exactamente lo que estás guardando. Un token de la API de WhatsApp escribe a los clientes en nombre del negocio. No es una clave de lectura: es la capacidad de hablarle a la clientela de tu cliente haciéndose pasar por él.
La objeción razonable es: «la base está protegida, nadie de fuera entra». Y es cierto, y no alcanza, porque las filtraciones de esta clase no suelen venir de fuera.
| Por dónde se escapa | ¿Requiere entrar al servidor? |
|---|---|
| Una copia de seguridad que se filtra | No |
| Un volcado para depurar un error | No |
| Una consulta de más en una consola compartida | No |
Cualquiera de las tres alcanza para que alguien le hable a la clientela de un cliente. Ninguna de las tres es un ataque.
Una promesa escrita antes de poder cumplirla
Esta parte es sobre cómo se trabaja, no sobre criptografía.
La columna donde viven estas credenciales se creó mucho antes de que hubiera un solo canal conectado de verdad. Y al crearla quedó escrito, ahí mismo: «van cifrados en la aplicación cuando existan: aquí nunca en claro».
Durante meses no hubo con qué cumplirlo, porque no había nada que guardar. El día que hubo un canal real, la promesa estaba esperando escrita en el sitio donde alguien iba a mirar.
Es una técnica barata y que funciona: cuando sabes que algo hará falta y todavía no toca, escríbelo donde se va a leer. No en un documento aparte: en la línea de código que lo va a necesitar.
Cifrar no basta: hay que autenticar
La primera decisión técnica se hace mal a menudo, por copiar un ejemplo viejo de internet.
Hay modos de cifrado que solo cifran y modos que además autentican. La diferencia se ve en qué pasa cuando alguien manipula el dato guardado.
Con un modo que solo cifra, un dato manipulado se descifra igual y devuelve basura. Y esa basura sigue su camino: el resto del programa la trata como un token bueno, la manda a Meta, y el error que aparece tres capas más allá no se parece en nada a la causa.
Con un modo autenticado, el dato manipulado falla al descifrarse. Se para ahí, con un error que dice lo que pasó.
Nosotros usamos AES-256-GCM. La regla, sin tecnicismos: si el modo que eliges no comprueba la integridad, tu sistema no distingue un dato corrupto de uno bueno.
La llave se lee al usarla, no al arrancar
Segunda decisión, y no es de seguridad: es de no tumbar el servidor.
Lo natural es leer la clave secreta cuando el módulo se carga, al arrancar. Y cargar los módulos es lo primero que hace el servidor al encenderse.
Si la clave falta, la excepción salta en ese momento y tumba el proceso entero, por una variable que quizá ninguna petición de esa hora iba a necesitar. El sitio público, que no tiene nada que ver con los canales, se cae también.
Leyéndola en cada uso, lo que falla es la operación que la necesitaba, con un error concreto, y el resto del sistema sigue funcionando.
Y ya que se comprueba, se comprueba bien: si la clave tiene la longitud equivocada, el mensaje lo dice con las dos cifras —lo que debería medir y lo que mide—. Sin eso, la biblioteca de cifrado suelta un error sobre longitudes de búfer que no menciona ni la variable ni el problema real, y alguien pierde una hora.
Un error de configuración tiene que nombrar la configuración. Casi ninguno lo hace.
El número que hace posible cambiar de idea
La quinta decisión casi nadie la toma a tiempo.
El dato cifrado se guarda con una versión delante: un «v1» al principio de la cadena. Hoy no sirve para nada. Sirve el día que haya que cambiar el algoritmo o rotar la clave.
Con la versión, lo viejo se sigue pudiendo leer mientras lo nuevo ya se escribe. La migración es gradual y sin ventana de riesgo: cada fila se moderniza cuando le toca.
Sin ella, rotar obliga a migrar todas las filas de golpe, en una operación que tiene que salir bien a la primera, con el servicio parado y sin poder volver atrás si algo falla a mitad.
Cuesta tres caracteres escribirlo el primer día. Cuesta un fin de semana no haberlo hecho.
Qué hacer entonces
- Mira si tus tokens de terceros están en claro. Si lo están, la siguiente copia de seguridad que salga de tu servidor los lleva dentro.
- Usa un modo de cifrado autenticado. Si el tuyo no comprueba la integridad, un dato corrupto te llega disfrazado de bueno.
- Lee los secretos al usarlos, no al arrancar. Una variable que falta no debería tumbar el sitio entero.
- Que el error nombre la variable. Con lo que mide y lo que debería medir.
- Pon una versión delante del formato. Hoy no hace nada; el día que rotes la clave te ahorra parar el servicio.
Esta nota sale de nuestro trabajo en Desarrollo de Software a medida.