Seguridad, GDPR y Compliance: Cómo Protegemos Cada Byte
Turnstile, Content Security Policy, OAuth PKCE, aislamiento por tenant, cookie consent, derecho al olvido y premium feature guards — la seguridad multi-capa de Cadences explicada pieza a pieza.
Gonzalo Monzón
· Fundador & CTO
La seguridad no es una feature que se añade después. En Cadences, es una decisión arquitectónica que afecta cada capa del stack: desde cómo se aíslan los datos de cada organización hasta cómo se valida un clic en un botón de registro. Este artículo explica el modelo de seguridad completo.
🛡️ Modelo de Defensa en Profundidad
Cadences implementa 7 capas de seguridad independientes. Si una falla, las demás siguen protegiendo. No hay un single point of failure en la cadena de seguridad.
Mapa de Seguridad Multi-Capa
Cada petición que llega a Cadences atraviesa múltiples capas de verificación antes de tocar un solo dato:
| Capa | Mecanismo | Protección |
|---|---|---|
| 1. Edge | Cloudflare WAF + DDoS | Ataques volumétricos, SQL injection a nivel HTTP |
| 2. Bot Protection | Turnstile (invisible) | Bots, scraping, registros falsos |
| 3. Autenticación | OAuth 2.0 + PKCE + JWT | Acceso no autorizado, session hijacking |
| 4. Autorización | RBAC + Feature Guards | Escalación de privilegios, acceso a features premium |
| 5. Aislamiento | D1 per tenant + V8 isolates | Cross-tenant data leak |
| 6. Transporte | TLS 1.3 + HSTS + CSP | MITM, XSS, clickjacking |
| 7. Secretos | Cloudflare Secrets + env vars | Exposición de API keys, tokens |
Turnstile: Protección Anti-Bot Invisible
Cadences utiliza Cloudflare Turnstile en lugar de CAPTCHAs tradicionales. La diferencia es crítica: Turnstile verifica que el usuario es humano sin interrumpir la experiencia. No hay puzzles, no hay "selecciona los semáforos".
CAPTCHA Tradicional
- ❌ Interrumpe el flujo del usuario
- ❌ Accesibilidad mediocre
- ❌ Google rastrea al usuario
- ❌ Tasa de abandono 8-15%
Cloudflare Turnstile
- ✅ Invisible — cero fricción
- ✅ Accesible por defecto
- ✅ Sin tracking de terceros
- ✅ Tasa de abandono ~0%
async function verifyTurnstile(token: string, ip: string) {
const response = await fetch(
'https://challenges.cloudflare.com/turnstile/v0/siteverify',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
secret: env.TURNSTILE_SECRET_KEY,
response: token,
remoteip: ip,
}),
}
);
const result = await response.json();
if (!result.success) {
throw new Error('Bot detected — request rejected');
}
return result;
} Turnstile se aplica en todos los formularios críticos: registro, login, contacto y pagos. El token se verifica server-side en el Worker, nunca en el cliente.
Autenticación: OAuth 2.0 + PKCE + JWT
Cadences soporta dos flujos de autenticación distintos según el contexto:
🌐 Web App (GIS Flow)
- 1. Redirect a Google OAuth
- 2. Google devuelve auth code
- 3. Worker valida code + client_secret
- 4. Se genera JWT firmado con HMAC-SHA256
- 5. JWT incluye orgId + userId + role + exp
🖥️ Desktop (PKCE Flow)
- 1. Genera code_verifier + code_challenge
- 2. Abre browser con challenge
- 3. Callback en localhost recibe code
- 4. Exchange code + verifier por tokens
- 5. Sin client_secret en el dispositivo
⚠️ ¿Por qué PKCE para Desktop?
Las apps de escritorio no pueden almacenar un client_secret de forma segura — cualquier usuario puede descompilar el binario. PKCE (Proof Key for Code Exchange) elimina esa necesidad: el challenge criptográfico reemplaza al secret, y solo el proceso que inició el flujo puede completarlo.
Premium Feature Guards
No todos los usuarios tienen acceso a las mismas funcionalidades. Cadences implementa un sistema de feature guards que protege las APIs costosas y las funcionalidades premium:
class PremiumAPIAccessError extends Error {
constructor(feature: string) {
super(`Premium feature "${feature}" not available`);
this.name = 'PremiumAPIAccessError';
}
}
function requirePremiumFeature(org: Org, feature: string) {
const allowed = org.plan?.features || [];
if (!allowed.includes(feature)) {
throw new PremiumAPIAccessError(feature);
}
}
// Ejemplo de uso en endpoint de Voice AI
requirePremiumFeature(org, 'voice_calls');
requirePremiumFeature(org, 'elevenlabs_tts'); Esto es especialmente importante para las APIs que tienen coste por uso (ElevenLabs, Twilio, OpenAI). Un usuario del plan gratuito no puede generar llamadas de voz por mucho que conozca la URL del endpoint.
Plan Free
CRM básico, 1 storefront, agentes IA limitados, sin voice, sin TTS
Plan Pro
Voice calls, TTS, agentes ilimitados, múltiples storefronts, webhooks
Plan Enterprise
SSO, API access, custom agents, dedicated support, SLA 99.9%
Aislamiento Total de Datos
El aislamiento de datos en Cadences no es un filtro de software — es una garantía arquitectónica. Cada organización tiene su propia base de datos D1 (SQLite en el edge). No hay WHERE org_id = ? — toda la base de datos pertenece a un solo tenant.
Data Isolation
Imposibilidad física de acceder a datos de otro tenant. No hay cross-tenant queries porque no hay tablas compartidas.
Compute Isolation
Cada request ejecuta en un V8 isolate independiente con sus propios límites de CPU y memoria.
Storage Isolation
Archivos en R2 bajo prefix por organización. KV namespaces con org-scoped keys. Sin posibilidad de colisión.
Auth Isolation
JWT firmados por org con HMAC-SHA256. Un token de org A no funciona contra org B, nunca.
Content Security Policy y Headers
Cada respuesta HTTP de Cadences incluye headers de seguridad que bloquean ataques antes de que el navegador ejecute código malicioso:
// Content Security Policy — controla qué puede cargar el navegador
Content-Security-Policy:
default-src 'self';
script-src 'self' 'unsafe-inline' challenges.cloudflare.com;
style-src 'self' 'unsafe-inline' fonts.googleapis.com;
img-src 'self' data: images.unsplash.com *.googleusercontent.com;
connect-src 'self' *.cadences.app api.elevenlabs.io;
frame-src challenges.cloudflare.com;
// Otros headers de seguridad
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(self), geolocation=() | Header | Qué previene |
|---|---|
| Content-Security-Policy | XSS, inyección de scripts, data exfiltration |
| Strict-Transport-Security | Downgrade attacks, MITM en HTTP |
| X-Frame-Options: DENY | Clickjacking via iframes |
| X-Content-Type-Options | MIME sniffing attacks |
| Permissions-Policy | Acceso no autorizado a cámara, micro, GPS |
En las apps Electron (CadencesLab, Audio Hub), se aplica además context isolation: el código de la app no tiene acceso directo a las APIs de Node.js. Toda la comunicación pasa por un preload bridge con IPC tipado.
GDPR: Cumplimiento Real, No Solo Banner
El GDPR no se cumple con un banner de cookies. Se cumple con decisiones arquitectónicas que permiten ejercer cada derecho que la regulación establece:
📋 Derecho de Acceso (Art. 15)
Exportación completa de datos del usuario en formato JSON/CSV. Un botón en Synapse Studio genera el paquete completo: contactos, deals, actividades, archivos.
✏️ Derecho de Rectificación (Art. 16)
Todos los datos son editables por el usuario propietario. Sin campos bloqueados, sin procesos opacos. Edita, guarda, listo.
🗑️ Derecho al Olvido (Art. 17)
Aquí es donde la arquitectura database-per-tenant brilla. ¿Quieres eliminar todos los datos de una organización?
// GDPR Article 17: Right to erasure
await env.CF_API.deleteD1Database(org.dbId);
await env.R2.deletePrefix(`org/${orgId}/`);
await env.KV.deletePrefix(`org:${orgId}:`);
// Toda la organización desaparece. No hay restos. No hay soft-delete. No hay flags. DROP DATABASE. Aislamiento total significa eliminación total.
📦 Derecho a la Portabilidad (Art. 20)
Exportación en formatos estándar (JSON, CSV) de todos los datos del usuario. Compatible con importación en otros CRMs.
🍪 Consentimiento de Cookies (Art. 7)
Banner de consentimiento en cada Storefront. Sin tracking hasta que el usuario acepta explícitamente. Google Analytics y scripts de terceros bloqueados por defecto.
Gestión de Secretos
Cadences maneja docenas de API keys y secrets de servicios externos: Google OAuth, Twilio, ElevenLabs, Stripe, DeepSeek, OpenAI, Anthropic. Ninguno de estos secretos aparece en el código fuente:
✓ Cómo se almacenan
- • Cloudflare Secrets (encrypted at rest)
- • Variables de entorno en wrangler.toml (dev)
- • Secrets per-environment (staging/production)
- • Rotación periódica de tokens OAuth
✕ Nunca se hace
- • Hardcoded secrets en código fuente
- • Secrets en localStorage o cookies
- • API keys en URLs o query params
- • Logs con datos sensibles
Rate Limiting con Durable Objects
Cada organización tiene su propio Durable Object de rate limiting. No compartimos contadores entre tenants. Esto significa:
| Endpoint | Límite | Ventana |
|---|---|---|
| API general | 1.000 req | por minuto / org |
| Auth (login/register) | 10 req | por minuto / IP |
| ElevenLabs TTS | 50 req | por hora / org (plan Pro) |
| Voice Calls (Twilio) | 20 calls | por hora / org |
| AI Agents | 100 exec | por hora / org |
| Webhook incoming | 500 req | por hora / org |
El rate limiter usa sliding window implementado con Durable Objects. Cada org tiene su propio DO, lo que significa que un abuso de org A no afecta a org B (no hay noisy neighbor).
Checklist de Seguridad Completo
🔐 Autenticación
- ✅ OAuth 2.0 con Google
- ✅ PKCE para apps desktop
- ✅ JWT con expiración configurable
- ✅ Refresh tokens cifrados
- ✅ Session invalidation server-side
🛡️ Infraestructura
- ✅ Cloudflare WAF + DDoS protection
- ✅ TLS 1.3 everywhere
- ✅ HSTS with preload
- ✅ Zero trust networking
- ✅ Edge-native (sin servidores propios)
📊 Datos
- ✅ Database per tenant
- ✅ Encryption at rest (D1)
- ✅ Backup automático diario
- ✅ GDPR data export
- ✅ Right to erasure (DROP DB)
🖥️ Apps Desktop
- ✅ Context isolation (Electron)
- ✅ IPC bridge tipado
- ✅ No nodeIntegration
- ✅ CSP en renderer
- ✅ Auto-update firmado
¿Tu plataforma cumple con GDPR?
Si estás construyendo un SaaS y necesitas cumplir con regulaciones de privacidad, Cadences ya lo hace por ti. Toda organización que opera en Cadences hereda automáticamente el modelo de seguridad completo.
Empieza con CadencesConclusión
La seguridad en Cadences no es un checkbox — es una propiedad emergente de la arquitectura. El aislamiento por tenant no es un filtro SQL, es una database separada. La protección anti-bot no es un CAPTCHA irritante, es Turnstile invisible. El cumplimiento GDPR no es un banner de cookies, es la capacidad de hacer DROP DATABASE y que desaparezca todo.
Cada capa funciona independientemente. Si mañana se descubre una vulnerabilidad en Turnstile, las otras 6 capas siguen protegiendo. Si un JWT se compromete, el rate limiter y los feature guards siguen bloqueando acceso no autorizado. Defense in depth no es un buzzword — es la única forma seria de construir software en 2026.
La mejor seguridad es la que el usuario no nota pero el atacante no puede superar.
Gonzalo Monzón
Fundador & CTO de Cadences