Para equipos de seguridad y revisores de apps

Seguridad en Peel

La versión corta: el contenido del tablero se cifra en el navegador con una clave que vive en el fragmento del enlace, así que nuestros servidores guardan y retransmiten texto cifrado que no pueden leer. Aquí explicamos exactamente cómo, y dónde están los límites.

Resumen

  • El texto de las tarjetas, los nombres, los títulos de los tableros, los votos y los stickers se cifran con AES-256-GCM mediante una clave de tablero generada en el navegador. La clave viaja en el fragmento de la URL (#k=) y nunca se envía a un servidor.
  • Las acciones del facilitador, la cabecera del tablero y las instantáneas se firman con la clave Ed25519 del facilitador. El ID del tablero se deriva de esa clave, así que los clientes detectan cualquier sustitución de clave.
  • Las tarjetas ocultas están selladas para el facilitador (sealed box X25519) hasta la revelación, y vinculadas mediante compromisos con sal para que el texto revelado no pueda cambiarse.
  • Anónimo por defecto: las operaciones no llevan ID de autor; los votos y reacciones usan un ID aleatorio por tablero.
  • Los participantes nunca se autentican. Sin SDK de analítica, sin anuncios, sin scripts de terceros salvo Paddle.js en la página de pago.
  • Solo Cloudflare. Los tableros sin reclamar se eliminan 60 días después de la última visita.

Cómo fluyen los datos

El fragmento de una URL (todo lo que va después del #) lo gestiona el navegador y no forma parte de la petición HTTP. Ahí es donde Peel pone la clave del tablero.

Flujo de datos: la clave se lee localmente del enlace; solo el texto cifrado y unos metadatos mínimos cruzan la red.

Modelo de amenazas

Diseñamos para que un servidor totalmente comprometido o curioso, incluidos nosotros, sepa lo menos posible de lo que dice un equipo.

Qué protegemos

  • El texto de las tarjetas, los GIF elegidos y, en el modo con nombre, el nombre de quien escribe.
  • Los nombres y avatares de los participantes, el nombre del tablero y los títulos de plantillas personalizadas.
  • Quién votó o reaccionó a qué, y quién escribió cada tarjeta.
  • La integridad de la retro: las fases, las revelaciones y las decisiones del facilitador no se pueden falsificar.

Adversarios que tenemos en cuenta

  • Nuestros propios servidores, alguien de dentro con malas intenciones o quien acceda a nuestro almacenamiento: obtienen texto cifrado y metadatos.
  • Un atacante en la red: TLS en todas partes; la clave nunca cruza la red.
  • Un servidor que sustituye claves: el ID del tablero se deriva de la clave pública del facilitador y los clientes verifican la cabecera firmada.
  • Un participante que quiere fisgar o falsificar: las tarjetas ocultas están selladas para el facilitador; las operaciones del facilitador requieren su firma; editar una tarjeta requiere la clave de esa tarjeta.
  • Un facilitador que republica por una persona desconectada: los compromisos le impiden cambiar el texto.

Fuera de alcance, con honestidad

  • Cualquiera que tenga el enlace de participante puede leer el tablero. El enlace es el control de acceso. Compártelo con el mismo cuidado que el propio tablero.
  • Un dispositivo comprometido, una extensión maliciosa del navegador o alguien mirando por encima del hombro.
  • El análisis de tráfico: el servidor ve tiempos, tamaños y recuentos (consulta el mapa de datos).
  • La denegación de servicio por parte del servidor: puede descartar o retrasar mensajes, pero no leerlos ni falsificarlos.

Criptografía

Todas las primitivas vienen de la API WebCrypto del navegador. Sin criptografía casera ni bibliotecas criptográficas de terceros.

ClaveAlgoritmoUso
K_boardAES-256-GCM, IV aleatorio de 96 bitsCifra cada operación, instantánea y actualización de presencia. Los datos adicionales vinculan el ID del tablero, el tipo de operación y el ID de la operación, así que un texto cifrado no puede reutilizarse en otro tablero u otra posición. Vive solo en el fragmento del enlace #k=.
K_ownerEd25519La autoridad del facilitador. Firma las operaciones del facilitador (fase, temporizador, foco, plantilla, ajustes, apertura de votos, ocultar una tarjeta), la cabecera del tablero y las instantáneas. Un contador estrictamente creciente impide la repetición. Solo en el enlace de facilitador (&o=).
ID del tableroSHA-256, primeros 80 bits, base32Se deriva de la clave pública del facilitador, así que el propio ID demuestra qué clave es dueña del tablero. Los clientes rechazan una cabecera cuya clave no genere ese ID.
K_facSealed box X25519: X25519 efímera + HKDF-SHA256 + AES-256-GCMLas tarjetas ocultas se sellan con la clave pública del facilitador mientras se escribe. Solo el enlace de facilitador (&f=) puede abrirlas.
Claves de tarjetaEd25519, una clave por tarjetaSolo la tiene quien escribió la tarjeta. Las ediciones y la revelación se firman con ella: autenticidad sin identidad.
CompromisosHMAC-SHA256 con una sal aleatoria de 128 bitsUna tarjeta oculta publica un compromiso sobre su contenido. En la revelación se publican el contenido y la sal, y cada cliente los comprueba, así que nadie puede cambiar el texto.
PresenciaAES-256-GCM con K_boardLos nombres, avatares e indicadores de escritura se cifran como todo lo demás.
Paquete de clavesHKDF-SHA256 a partir del PRF de la llave de acceso o del código de recuperación, AES-256-GCMLos facilitadores con sesión iniciada pueden sincronizar sus claves de tablero entre dispositivos. El paquete se cifra en el dispositivo; el servidor solo guarda texto cifrado y claves envueltas.

Los mensajes de firma están separados por dominio (por ejemplo peel/sig/v1, peel/header/v1, peel/snap/v1) para que una firma hecha para un propósito no pueda reutilizarse para otro.

Tarjetas ocultas y la revelación

  1. Mientras se escribe, el navegador de quien escribe sella la tarjeta con la clave X25519 del facilitador y publica un compromiso con sal. El texto en claro se queda en su dispositivo.
  2. El resto de participantes ve una tarjeta oculta: no puede descifrarla, y el servidor tampoco.
  3. El navegador del facilitador puede abrir las tarjetas selladas (la vista previa “👁 solo tú”).
  4. En la revelación, cada autor vuelve a publicar su tarjeta cifrada con K_board, firmada con la clave de la tarjeta, junto con la sal.
  5. Si alguien está desconectado, el facilitador la publica en su nombre. Cada cliente comprueba el compromiso, así que el texto tiene que coincidir con lo que escribió su autor.

Como el facilitador puede técnicamente ver las tarjetas antes de tiempo, cada tablero muestra a todo el mundo el aviso “el facilitador puede ver las tarjetas” mientras haya tarjetas ocultas. No es un ajuste que se pueda ocultar.

Anonimato

  • Las operaciones no llevan ID de autor. El servidor no puede vincular una tarjeta con una persona y, por defecto, el facilitador tampoco.
  • Los votos y reacciones se asocian a un ID aleatorio por tablero que no está vinculado a ningún nombre.
  • Los indicadores de escritura muestran que alguien escribe, nunca qué.
  • El modo con nombre es un ajuste explícito del tablero; en ese caso, el nombre del autor viaja dentro de la tarjeta cifrada.
  • Los participantes nunca inician sesión, así que no hay ninguna cuenta que cruzar.

Mapa de datos

Todo lo que guardamos, dónde está, quién puede leerlo y cuánto tiempo se conserva.

DatosDóndeQuién puede leerlosConservación
Tarjetas, votos, reacciones, stickers, acciones, nombre del tablero, títulos de plantillas personalizadasAlmacenamiento de Durable Object, como texto cifradoQuien tenga el enlace del tableroHasta que se elimina el tablero
Sobre de la operación: tipo, secuencia y hora del servidor, tamaño, contador del facilitadorAlmacenamiento de Durable ObjectPeelHasta que se elimina el tablero
Nombres y avatares de los participantes, escritura en cursoRetransmitidos como texto cifrado; en memoria mientras dura la conexiónQuien tenga el enlace del tableroMientras dura la conexión
Estado del tablero: fase, número de participantes y tarjetas, ID de plantilla del catálogo, indicador de bloqueo, fechas de creación y caducidadDurable Object, D1; mensajes de Slack/Teams si está instaladoPeel; tu canal de Slack/TeamsVida del tablero
Cuenta de facilitador: ID del proveedor, nombre, correo si se comparte, proveedores vinculados, fecha de creación, sesiónD1PeelHasta que eliminas la cuenta
Paquete de claves y claves envueltasD1, como texto cifradoSolo tú (llave de acceso o código de recuperación)Hasta que eliminas la cuenta
Plan, estado de la suscripción, IDs de cliente y de suscripción de PaddleD1; PaddlePeel, PaddleLo que exija la normativa fiscal
IDs de espacio de trabajo, canal y mensaje de Slack/Teams; token del bot (cifrado con AES-GCM)D1PeelHasta la desinstalación
Dirección IPEdge de Cloudflare, de forma transitoria (entrega, límites de uso)Cloudflare, el limitador de uso de PeelNo se guarda en nuestras bases de datos
Contadores diarios (tableros creados, fases alcanzadas)D1PeelSolo agregados, sin identificadores

Qué puede y qué no puede hacer nuestro servidor

Puede

  • Ver los tipos de operación, tamaños, tiempos, la fase, el número de participantes y tarjetas, el ID de plantilla del catálogo y el indicador de bloqueo.
  • Descartar, retrasar o negarse a entregar operaciones (denegación de servicio).
  • Ver direcciones IP en el borde de la red.
  • Contar tableros y fases alcanzadas, de forma agregada.
  • Eliminar un tablero (caducidad, denuncias de abuso).

No puede

  • Leer el texto de las tarjetas, nombres, títulos de tableros, títulos de plantillas personalizadas, votos ni stickers.
  • Leer las tarjetas ocultas antes de la revelación (ni siquiera después).
  • Falsificar acciones del facilitador: requieren su firma.
  • Colar sus propias claves: el ID del tablero lo delataría.
  • Cambiar el texto revelado de una tarjeta: los compromisos y las firmas de tarjeta lo delatarían.
  • Saber quién escribió cada tarjeta.

Como en cualquier app web, confías en el código que servimos. Mantenemos esa superficie pequeña: una Content Security Policy estricta, script-src limitado a nuestro propio origen, ningún script de terceros, y el protocolo está abierto a revisión si se solicita.

Slack y Microsoft Teams

  • Los mensajes llevan el enlace del tablero y metadatos (título, fase, recuentos). El texto de las tarjetas solo se envía cuando el facilitador publica un resumen y lo confirma.
  • La tarjeta para unirse contiene el enlace de participante, que incluye la clave. Cualquiera que pueda leer ese canal puede unirse, igual que si se pegara allí el enlace.
  • Las vistas previas de enlaces solo muestran la fase y los recuentos, nunca el contenido.
  • Permisos de Slack: commands, chat:write, links:read, links:write; users:read solo cuando un equipo activa las menciones.
  • Los tokens de bot se cifran en reposo (AES-GCM, con la clave guardada como secreto del Worker). Las firmas de las peticiones de Slack y los tokens de Bot Framework se verifican en cada petición.
  • Al desinstalar la app se dejan de publicar mensajes y se eliminan sus tokens.

Web e infraestructura

  • Solo Cloudflare: Pages, Workers, Durable Objects, D1, R2 y KV en la cuenta de 1801 Labs. Ningún otro servidor.
  • TLS en todas partes, HSTS y una Content Security Policy estricta.
  • Sin SDK de analítica, sin anuncios, sin scripts de terceros. La única excepción es Paddle.js, que se carga solo en la página de pago.
  • Una sola cookie, solo para facilitadores con sesión iniciada: peel_session, httpOnly, Secure, SameSite=Lax.
  • La búsqueda de GIF y los archivos multimedia pasan por nuestra API, así que las direcciones IP de los participantes nunca llegan a GIPHY.
  • Fuentes y recursos alojados por nosotros. Sin fuentes de CDN ni píxeles de seguimiento.
  • Límites de uso por IP y por tablero; denuncias de abuso y bloqueo por parte del facilitador.

Cuentas y conservación

  • Los participantes nunca se autentican. Los facilitadores inician sesión con Google (o Entra ID a través de Teams) solo para conservar tableros o usar funciones de pago.
  • Una cuenta guarda un ID, el nombre y el correo del proveedor, y un paquete de claves cifrado que se desbloquea con una llave de acceso (WebAuthn PRF) o un código de recuperación. Iniciar sesión da la propiedad, no acceso al contenido.
  • Reclamar un tablero demuestra la propiedad con una firma del facilitador. Las claves del tablero nunca se envían.
  • Los tableros sin cuenta se eliminan 60 días después de la última visita; cada visita reinicia el plazo. Las alarmas de Durable Object borran el almacenamiento.
  • Eliminar tu cuenta borra las sesiones, el paquete de claves y tu biblioteca, y devuelve a tus tableros la caducidad de 60 días.

Divulgación responsable

¿Has encontrado algo? Avísanos primero y trabajaremos contigo. Confirmamos la recepción de los informes en un plazo de tres días laborables.

[email protected]

  • Danos un plazo razonable (nuestro objetivo son 90 días) para corregirlo antes de hacerlo público.
  • Haz pruebas con tus propios tableros y cuentas. No accedas a datos de otras personas ni degrades el servicio.
  • No emprenderemos acciones legales contra investigaciones de buena fe que sigan estas reglas.
  • Contacto legible por máquina: /.well-known/security.txt.

Los clientes del plan Empresa reciben un paquete de revisión de seguridad (respuestas a cuestionarios, subencargados, flujos de datos). DPA · Privacidad