Seguridad en qub

Fecha de entrada en vigor: 23 de septiembre de 2026 Versión: 1.1 — revisión de precisión de la implementación


Para investigadores — referencia rápida:

Los detalles completos están en §12 (Divulgación coordinada).


Quiénes somos

qub.social es operado por VSPRY AUSTRALIA PTY LIMITED (ABN 41 631 026 330), Level 38, 71 Eagle Street, Brisbane QLD 4000, Australia. Las referencias a "qub", "nosotros", "nos" y "nuestro" se refieren a esa entidad.

Contacto de seguridad: support@qub.social con el prefijo de asunto [SECURITY].


1. Nuestro enfoque

qub es infraestructura de confianza. El producto no vale nada si no es seguro, así que la seguridad no es una característica — es el sustrato. Esta página describe, en términos concretos, cómo protegemos nuestro stack, tus datos y la integridad del contenido sellado.

El valor de un compromiso temporal verificable crece a medida que una parte mayor de internet es generada por máquinas. Una transacción de almacenamiento verificada o un anclaje del registro de transparencia puede establecer que un texto cifrado existía a más tardar en la hora de su bloque; el artefacto sellado demuestra por separado la integridad del contenido, la vinculación con la ronda de drand y cualquier firma de autoría. Mantener separadas estas afirmaciones es la vara con la que se mide esta página.

No te pedimos que confíes en nosotros. Diseñamos para que la confianza requerida en nosotros sea lo más pequeña posible, y donde se requiere confianza explicamos exactamente qué se está confiando y por qué.

Tres principios guían cada decisión de diseño:


2. Modelo de amenazas

2.1 Contra qué protegemos

2.2 Contra qué no podemos proteger

Somos honestos sobre nuestros límites. qub no puede defender contra:


3. Criptografía del lado del cliente

En el flujo de mensajes predeterminado del navegador, el contenido se cifra antes de la solicitud de subida. Hay dos rutas explícitas distintas: /api/v1/seal de Builder envía deliberadamente el texto plano y una K generada por quien llama al Worker para sellarlos en memoria, y la preparación y cofirma de pactos envía el pacto estructurado y firmado al servicio para que este finalice el artefacto bilateral. Ninguna de estas excepciones debe confundirse con el cifrado de extremo a extremo de la ruta del navegador.

3.1 Cifrado timelock

qub usa tlock — cifrado basado en identidad, indexado a una ronda futura de la baliza drand. El cifrado se realiza en tu navegador usando la clave pública de la red drand; la clave de descifrado es liberada públicamente por la red drand solo cuando se alcanza la ronda objetivo. Nadie, incluidos nosotros, puede reconstruir la clave de descifrado por adelantado.

Apuntamos a la cadena quicknet:

La clave pública de la cadena quicknet y el genesis time están compilados en el cliente. No obtenemos los parámetros de la cadena en tiempo de ejecución, así que un nodo malicioso no puede sustituir una cadena que controlemos.

3.2 Cifrado simétrico

El esquema tlock envuelve una clave de contenido AES-256-GCM. AES-GCM provee cifrado autenticado: un solo bit volteado en el ciphertext causa que el descifrado falle, en vez de producir texto plano corrompido silenciosamente.

3.3 Serialización canónica

Las estructuras del protocolo se serializan mediante CBOR determinista (RFC 8949 §4.2, codificación determinista básica). Dos implementaciones que codifican la misma estructura lógica producen CBOR idéntico. Las cargas útiles selladas completas no son deterministas: tlock y el cifrado de la envoltura externa usan aleatoriedad nueva. El hash del cuerpo se calcula sobre los bytes sin procesar del cuerpo, mientras que la codificación canónica hace inequívocas las estructuras firmadas y de transmisión que lo rodean.

Escribimos el codificador CBOR a mano tanto para nuestra implementación cliente como para la del servidor en lugar de depender de una biblioteca de serialización genérica — el requerimiento es exactitud, no ergonomía, y se ejecutan tests de propiedad en ambas implementaciones para verificar que coinciden.

Un test de regresión afirma que el formato canónico de transmisión no contiene ninguna secuencia de bytes con la marca qub más allá de la clave de campo qub_id, primitiva del protocolo. El formato de transmisión es intencionalmente agnóstico de marca — cualquier lector conforme (el nuestro o el de un tercero) puede renderizar cualquier qub desde el almacenamiento permanente, independientemente de qué despliegue lo selló. El test es un trampolín que evita que un cambio futuro hornee accidentalmente una referencia de marca en bytes que, una vez en el almacenamiento permanente, no pueden reescribirse.

3.4 Hashing del cuerpo e integridad pre-revelación

Cada carga útil sellada lleva un hash SHA3-256 de los bytes sin procesar de su cuerpo. El hash está vinculado a qub_id y, cuando se habilita la firma de autoría, a la entrada de firma V2. Un lector lo vuelve a calcular después del descifrado y rechaza cualquier discrepancia.

El identificador de contenido de 32 bytes qub_id se deriva de una preimagen de 108 bytes que abarca la versión del protocolo, el tipo de contenido, las marcas de tiempo de creación y desbloqueo, la marca temporal opcional del resultado (o su centinela cero), la ronda de drand objetivo, el hash del cuerpo y el SHA3-256 del título opcional normalizado en NFC. Un gateway o CDN no puede modificar de forma coherente ningún campo vinculado y superar la nueva derivación. Los títulos están limitados a 100 puntos de código NFC y se rechaza en ellos la clase compartida de puntos de código hostiles o de control (incluidos los controles bidireccionales, los caracteres de ancho cero, el bloque de etiquetas, BOM, C0, C1 y DEL).

3.5 Firma (ML-DSA-65)

La firma de autoría usa ML-DSA-65 (FIPS 204), un esquema de firma post-cuántico estandarizado por NIST. Elegimos deliberadamente un primitivo post-cuántico para la firma porque el contenido sellado es permanente: una firma que verifica hoy debe seguir verificando dentro de décadas, incluso después de que las computadoras cuánticas a gran escala se vuelvan prácticas.

Las claves de firma se generan en el navegador. El secreto local se envuelve bajo una clave WebCrypto no extraíble antes de almacenarse en IndexedDB. Si se usa la función de recuperación multidispositivo vinculada a la cuenta, se almacena en el servidor un blob portátil de clave cifrado con AEAD; el texto cifrado de su clave secreta queda vinculado al identificador inmutable de la cuenta, y el servicio valida la envoltura pública pero no puede descifrar el material secreto. Los bytes sin procesar de la clave privada no se envían al servidor. Las claves públicas y los registros de atestación se almacenan para la verificación y la presentación de la identidad.

El mismo descifrado tlock en el navegador se aplica dentro de la incrustación de qub: cuando un qub sellado se renderiza a través de <qub-embed> en una página de terceros, el descifrado igual sucede en el iframe de incrustación dentro del navegador del lector. La incrustación no cambia el modelo de confianza — el texto plano nunca se descifra en un servidor de qub.

3.6 Atribución pública — Opcional

Los qubs sellados no llevan ningún puntero on-chain a su creador a menos que el creador elija explícitamente adjuntar uno. Cuando sellas un qub, la app de referencia emite una etiqueta Author de almacenamiento (un fingerprint hexadecimal de 64 caracteres de tu clave pública de firma) solo cuando "Atribución pública" está activada en el paso del selector de fecha. Con el toggle desactivado — el predeterminado — no se escribe ninguna etiqueta Author y el qub queda sin atribución en el almacenamiento permanente: nada en el almacenamiento vincula la subida con tu handle, tu correo electrónico o tus otros qubs. Con el toggle activado, el fingerprint se resuelve a tu @handle a través de la cadena de attestation en §6.3 / §10 y la cuenta regresiva del lector muestra "Sellado por @{handle}" antes de la revelación.

Esto es una protección deliberada contra el riesgo de enumeración que crearía una etiqueta Author siempre activada: un tercero que descubra el fingerprint de un creador podría, de otro modo, hacer grep en el almacenamiento permanente por la etiqueta y reconstruir la totalidad del output histórico de ese creador. La atribución opcional cierra ese canal — solo los qubs que el creador elige explícitamente atribuir aparecen bajo un fingerprint en el almacenamiento permanente.

La página de perfil /u/{handle} es una tarjeta de identidad verificada — handle, nombre para mostrar y URL opcionales, badge "correo verificado" (sin la dirección), y la forma corta del fingerprint criptográfico. No lista los qubs de un creador. Los visitantes que quieran ver un qub específico de un creador siguen la URL de entrega de ese qub directamente.

3.7 Envoltura externa de cifrado

Incluso después de que el descifrado timelock sea matemáticamente posible —una vez publicada la firma de drand de la ronda vinculada—, la capa timelock canónica por sí sola permitiría a un indexador descifrar en masa los qubs que pueda encontrar. La entrega privada cierra ese canal con una capa simétrica adicional alrededor de los bytes cifrados con timelock (Protocolo §13). La entrega pública omite deliberadamente la envoltura para que los enlaces de notificación, incrustación y descubrimiento funcionen sin un fragmento secreto.

La envoltura usa AES-256-GCM, un cifrado autenticado estandarizado por NIST, con una clave fresca de 256 bits K generada por qub por el CSPRNG de tu navegador. K está vinculada al qub_id del qub como datos adicionales autenticados, así que una clave de un qub no puede reutilizarse para descifrar un qub diferente.

K nunca llega a nuestros servidores en el flujo privado predeterminado del navegador. Está codificada en el fragmento de URL del enlace para compartir (https://qub.social/c/<tx_id>#<base64url(K)>). Los navegadores no transmiten los fragmentos de URL a los servidores —RFC 3986 coloca el fragmento fuera de la solicitud—, así que qub.social, los gateways de almacenamiento, los CDN y el monitoreo de solicitudes no ven K en ese flujo. El OuterWrapper almacenado es CBOR estructurado reconocible, pero su campo de texto cifrado autenticado oculta la estructura interna de SealedQub y no puede abrirse sin K.

Consecuencias netas:

El endpoint del lado del servidor /api/v1/seal del Worker (usado por agentes de IA y otros llamantes de la API) requiere que el llamante genere K con un CSPRNG, la conserve localmente y la suministre como wrapper_key_b64url. El Worker necesariamente ve tanto el texto plano como K en memoria en esta ruta explícitamente confiable, pero no persiste ninguno de los dos. Un Idempotency-Key obligatorio evita que una respuesta perdida cree un segundo qub facturado, mientras que la K conservada por el llamante puede combinarse con la URL sin fragmento reproducida. Esto difiere de la ruta de navegador por defecto, donde K nunca llega al Worker a menos que el creador habilite explícitamente la recuperación.


4. Transporte y borde

4.1 TLS

El tráfico del navegador a qub se sirve por HTTPS en el borde de Cloudflare. Las respuestas establecen HTTP Strict Transport Security (max-age=63072000; includeSubDomains; preload). La versión exacta de TLS y el conjunto de cifrado negociados se rigen por la configuración activa del borde, no por afirmaciones del código de la aplicación. No exponemos un servidor de origen alcanzable por separado.

4.2 Seguridad del contenido

El cliente compilado se sirve con encabezados estrictos de tipo de contenido y de caché. La shell SPA es de un solo origen. No incrustamos scripts de terceros para analítica o publicidad. Los dos puntos de contacto con terceros en el producto están ambos limitados de forma estrecha: el flujo de compra deja la SPA por completo con una redirección de página completa al checkout alojado por Stripe (https://checkout.stripe.com/…) — la UI de Stripe nunca se ejecuta en nuestro origen y nunca vemos los datos de la tarjeta — y el flujo de sellado carga el widget Turnstile de Cloudflare, una alternativa de CAPTCHA respetuosa con la privacidad que Cloudflare renderiza dentro de su propio iframe sandboxed. Ninguna de las partes puede leer el resto de la página.

El iframe de incrustación de qub (servido desde qub.social/embed/{tx_id} y cargado en sitios de terceros por embed.js) lleva su propia Content-Security-Policy. Su lista permitida de connect-src es 'self', https://qub.social, https://arweave.net, https://ar-io.dev, https://permagate.io, https://api.drand.sh y https://drand.cloudflare.com. El iframe se ejecuta con sandbox="allow-scripts allow-top-navigation-by-user-activation" (sin allow-same-origin): la página anfitriona no puede leer su DOM, y el iframe no puede navegar la página anfitriona salvo tras una acción del usuario.

4.3 CORS y alcance de fetch

El cliente del navegador hace solicitudes fetch solo a:

Los destinos de la incrustación se aplican mediante su CSP. Los destinos previstos de la SPA principal están fijados en el código y la configuración y se ejercitan mediante comprobaciones de navegador e integración; Subresource Integrity no es un control de destinos de red.

La incrustación obtiene los bytes almacenados a través de los orígenes de qub o almacenamiento permitidos, desenvuelve las cargas útiles privadas en el navegador usando K del fragmento de su URL y obtiene de los dos orígenes de drand permitidos las firmas de la ronda en el momento de revelación. La SPA principal usa el conjunto alternativo de cuatro endpoints de config/drand-endpoints.json (drand.cloudflare.com, api.drand.sh, api2.drand.sh y api3.drand.sh) para que la caída de uno no impida la revelación. La CSP de la incrustación deniega las conexiones ajenas a su lista explícita.


5. Infraestructura del lado del servidor

5.1 Borde serverless

Nuestra API se ejecuta enteramente en un runtime serverless gestionado en el borde. No hay VMs, ni contenedores, ni procesos de servidor persistentes que administremos. Esto reduce drásticamente la superficie de ataque de la que somos responsables: no ejecutamos un sistema operativo, un servidor web ni un runtime de aplicación que debamos parchear.

Se aplica un middleware público-CORS separado Access-Control-Allow-Origin: * al siguiente conjunto de ruta implementada: /embed.js, /embed/v1.js, todo debajo /embed/; /api/v1/telemetry; /api/v1/openapi.json; todo debajo /api/v1/qub/ (incluyendo bytes, metadatos, prueba, participación, notificación y subrutas push); todo debajo de /api/v1/log/; búsquedas de manejadores públicos bajo /api/v1/handle/; y el avatar público lee debajo /api/v1/identity/avatar/. Sus permisos de prevuelo GET, POST, y OPTIONS con el Content-Type encabezado de solicitud. Esta superficie basada en prefijos es más amplia que solo las llamadas que actualmente realiza el embed, por lo que cada manejador por debajo de esos prefijos debe seguir aplicando su propia validación, autenticación, límites de tasa y controles de abuso. Otros caminos de la API mantienen la política CORS restringida de qub.social.

5.2 Almacenamiento

El flujo de mensajes predeterminado del navegador no conserva texto plano en la infraestructura de qub. /api/v1/seal de Builder procesa el texto plano y K en memoria, pero no conserva ninguno. La preparación de pactos necesariamente almacena el pacto estructurado y firmado hasta que se cofirma, se retira o caduca. La recuperación opcional almacena una capacidad de entrega (el enlace completo con fragmento) para recuperarla más tarde. Por tanto, no describimos todo el nivel de almacenamiento como «solo metadatos».

5.3 Secretos

Los secretos (billeteras de firma, tokens de proveedores y claves HMAC) se suministran mediante vinculaciones de secretos o entorno de la plataforma, no mediante el control de versiones. Los componentes en ejecución reciben solo las vinculaciones que necesitan. Los procedimientos de rotación y solapamiento son específicos de cada componente; no afirmamos que exista un único mecanismo universal de rotación automática o auditada.

5.4 Logging y telemetría

Se escriben logs JSON estructurados en cada solicitud de API con un correlation ID expuesto en el encabezado de respuesta X-Request-Id. La telemetría del cliente es anónima — sin identificador de dispositivo, sin dirección IP, sin vista previa del contenido. Los eventos se almacenan en memoria y se envían en base a mejor esfuerzo; un envío fallido se descarta, no se reintenta. La telemetría está diseñada para ser desactivable a nivel de red sin afectar al producto.


6. Autenticación

6.1 Inicio de sesión por magic-link

El inicio de sesión usa un token de un solo uso firmado con HMAC y enviado a tu bandeja de correo. El enlace es válido durante 15 minutos y su canje se reclama de forma atómica, por lo que los usos simultáneos o repetidos fallan de forma segura. Si tiene éxito, el navegador recibe una cookie opaca __Host-qub_session con los atributos Secure, HttpOnly, SameSite=Strict y Path=/.

Las sesiones tienen un límite de inactividad de 30 días y un límite absoluto de 90 días, rotan después de 24 horas y solo aceptan la generación inmediatamente anterior durante un período de gracia de 120 segundos por pérdida de respuesta. Las modificaciones sensibles de la cuenta requieren haberse autenticado en los 10 minutos anteriores. El secreto de firma HMAC es una vinculación de la plataforma; una lectura exclusiva de los metadatos no permite por sí sola emitir un token válido.

6.2 API keys (plan Developer)

Las API keys de desarrollador usan el prefijo qub_sk_ para fácil reconocimiento y grepability. Cada clave:

Los endpoints administrativos de gestión de claves están protegidos detrás de una credencial admin separada.

6.3 Attestation por correo electrónico (firma de autoría)

Vincular una dirección de correo electrónico a una clave de firma requiere:

  1. La posesión de la clave privada de firma (firmas un desafío)
  2. La posesión de la bandeja de correo (introduces un código de 6 dígitos entregado por correo)

Cualquiera por separado es insuficiente. La revocación es un registro firmado en tu propia cuenta y entra en vigor de inmediato; los lectores que obtienen la attestation ven el estado revocado y muestran en consecuencia.


7. Pagos

La introducción y el procesamiento de los datos de la tarjeta se ejecutan dentro del checkout alojado por Stripe. Nunca recibimos números de tarjeta, fechas de vencimiento ni CVC. Sí almacenamos los identificadores de cliente y suscripción de Stripe, el estado de la suscripción y los datos del período en los registros de derechos y claves API para conciliar el acceso, las renovaciones, la medición, la cancelación y los reembolsos. Las declaraciones de privacidad y seguridad de Stripe rigen su tratamiento de los datos de pago.

El endpoint de sellado verifica el registro de derechos contra el identificador del dispositivo y, para usuarios autenticados, contra la identidad vinculada. Un derecho no puede reutilizarse entre dispositivos sin que el usuario lo restaure explícitamente vía inicio de sesión por magic-link.


8. Resistencia al abuso

8.1 Detección de bots

El flujo de sellado está protegido por una alternativa de CAPTCHA respetuosa con la privacidad que no usa cookies para tracking y no hace fingerprinting para publicidad. Un desafío fallido es rechazado por nuestro Worker en el borde antes de que ocurra cualquier procesamiento del lado del sellado.

8.2 Rate limiting

Los rate limits se aplican en varias capas:

Los contadores y las reclamaciones atómicas se distribuyen entre KV, Durable Objects y las vinculaciones de límites de tasa de la plataforma según los requisitos de coherencia del endpoint. Las solicitudes limitadas devuelven 429; los endpoints que pueden calcular una ventana de reintento incluyen Retry-After.

8.3 Moderación de contenido

La ruta de carga de navegador predeterminada no puede escanear el cuerpo: solo recibe el artefacto sellado por el cliente. El Constructor /api/v1/seal la ruta ve el texto en claro de forma transitoria, y el staging de pact mantiene los términos estructurados hasta la finalización, pero esas excepciones de confianza no convierten la ruta de carga general ciega a los bytes en un escáner de contenido. La moderación operativa es una lista de denegación en la capa del visor: un qub en la lista de denegación es rechazado por nuestro visor independientemente de si la carga útil almacenada sigue siendo accesible. La inclusión en la lista de denegación no retira bytes duraderos, entradas del registro de transparencia ni datos de red permanentes ya publicados.

Los reportes de abuso tienen rate limit usando un hash unidireccional de la IP del reportante; no almacenamos las IPs en claro para este propósito.


9. Cadena de suministro e integridad de la build

9.1 Pinning del toolchain

Las versiones del compilador y del runtime están fijadas en la configuración del repositorio, y las dependencias se resuelven mediante lockfiles incorporados al repositorio. CI comprueba que los archivos generados estén actualizados y verifica invariantes sensibles a la reproducibilidad. No hacemos la afirmación más fuerte de que toda compilación limpia sea idéntica bit por bit en todas las máquinas compatibles.

9.2 Lints y análisis estático

El workspace habilita nuestros grupos de lints más estrictos al nivel deny. CI trata cada warning — incluyendo los warnings de enlaces de documentación — como un fallo de build. Esto es deliberado: usamos la severidad de los lints como un trampolín para regresiones sutiles.

9.3 Gates de CI

El flujo de trabajo de CI abarca formato y lints estrictos; pruebas de Rust, WASM/navegador, Worker, incrustación y API; comprobación de tipos; cobertura de código; comprobaciones de mutación e invariantes; análisis estático de dependencias y flujos de trabajo; comprobaciones de claves i18n, cobertura, deriva y puntos de código hostiles; actualización de documentación, API y base de conocimientos generadas; inventario de documentos y enlaces internos; presupuestos de estilos y bundles, y validación de OpenAPI. Algunas tareas de mutación costosas son programadas y no se ejecutan en cada push.

Un único resumen obligatorio ci permanece en rojo si falla cualquier tarea requerida. Los flujos de ramas protegidas y despliegue consumen ese resultado, en vez de duplicar un gate de seguridad más pequeño.

9.4 Mutation testing

Un job semanal ejecuta mutation testing contra los módulos puros críticos para la seguridad: hashing, CBOR canónico, sellado, desbloqueo, los newtypes del formato de transmisión, los validadores de tipos del protocolo, y el namespace de handles. El mutation testing responde "¿nuestro suite de tests detecta código sutilmente incorrecto?" — si una implementación mutada todavía pasa todos los tests, sabemos que tenemos una brecha de cobertura de tests y la abordamos.

9.5 Git hooks

Los hooks locales (pre-commit, pre-push) reflejan los gates de CI para que las regresiones se detecten antes de salir de la máquina del desarrollador. Los hooks se instalan vía un script del repo; no se omiten en nuestro workflow y CI es el gate autoritativo si se omiten.


10. Testing

El código crítico para la seguridad lleva tres tipos de tests:


11. Higiene de ramas y releases

Las ramas de funciones hacen avanzar staging solo mediante un pull request de Gate 1: ci obligatorio en verde, ninguna solicitud de cambios sin resolver, ningún conflicto de merge y un árbol limpio y revisado; el merge se aplasta y la rama se elimina. main avanza solo mediante el pull request de Gate 2 staging → main y conserva la ascendencia con un commit de merge. Los pushes directos a ramas no forman parte del flujo de publicación.

Los despliegues de staging y producción se activan desde los estados correspondientes de las ramas protegidas staging y main después de CI. El código de pull requests y las credenciales de forks no reciben secretos de despliegue.

Los secretos usados en los workflows de despliegue están limitados al entorno de despliegue por nuestra plataforma de CI. No están disponibles para los workflows de pull-request desde forks.


12. Divulgación coordinada

Si crees que has encontrado una vulnerabilidad de seguridad en qub, queremos enterarnos rápidamente y nos comprometemos a manejar el reporte de forma profesional.

Acusamos recibo dentro de los tres días hábiles y te mantenemos informado mientras investigamos. Con tu consentimiento, acreditamos a los reportantes en las notas de la versión.

12.1 Safe Harbor

Si tu investigación sigue las reglas anteriores (investigación de buena fe, sin daño a otros usuarios o al servicio, ventana razonable de divulgación), no emprenderemos acciones legales contra ti, y no le pediremos a las fuerzas del orden que lo hagan. Tratamos tu trabajo como pruebas autorizadas y preferimos que tú encuentres el bug a que lo encuentre alguien más.

Este Safe Harbor se aplica a:

No se aplica a la ingeniería social de los miembros del equipo de qub, las pruebas de denegación de servicio, ni acceder a los datos de otros usuarios más allá de lo necesario para demostrar el problema. Si no estás seguro de si algo cae dentro del Safe Harbor, pregunta primero usando el mismo prefijo de asunto [SECURITY].


13. Limitaciones honestas

La seguridad es una práctica, no un estado. Vale la pena nombrar directamente algunas limitaciones:


14. Cambios a esta página

Los cambios materiales se anotan actualizando la fecha de entrada en vigor en la parte superior. Cuando un cambio refleja una mejora concreta de seguridad, lo describimos brevemente en el changelog público. Cuando un cambio refleja una clarificación de política, describimos qué cambió y por qué.

Para preguntas sobre cualquier cosa en esta página, envía un correo a support@qub.social con el prefijo de asunto [SECURITY].


15. Registro de cambios

Versión Fecha de entrada en vigor Resumen
1.1 23 de septiembre de 2026 Se conciliaron con el sistema implementado las afirmaciones criptográficas, los modos de entrega, el almacenamiento, la CSP, las sesiones, las claves API, los pagos, CI y el flujo de publicación.
1.0 2 de mayo de 2026 Publicación inicial.