Criptografía en aplicaciones web, móviles y APIs: decisiones de diseño

Capítulo 10

Tiempo estimado de lectura: 12 minutos

+ Ejercicio

De primitivas a arquitectura: decisiones que sí cambian el resultado

En aplicaciones web, móviles y APIs, la criptografía rara vez falla por “el algoritmo”: falla por decisiones de diseño (dónde se guarda un token, qué se firma, qué se cifra, qué se valida y en qué orden). Este capítulo traduce necesidades típicas (sesión, antifraude, integridad, sincronización) a mecanismos concretos sin reinventar protocolos.

Mapa rápido: problema → mecanismo recomendado

NecesidadMecanismoErrores comunes
Sesión webCookie de sesión + flags segurosJWT en localStorage; cookies sin SameSite; no rotar sesión
API para SPA/móvilOAuth 2.0/OIDC (conceptual) + tokens firmadosInventar “tokens” propios; mezclar authn/authz; scopes mal definidos
Evitar CSRFSameSite + token CSRF (si aplica)Confiar solo en Referer; CSRF token sin atarlo a sesión
Integridad de eventos entrantes (webhooks)Firma HMAC o firma asimétrica + timestampFirmar solo parte del payload; no validar ventana temporal; comparar firmas inseguro
Confidencialidad de payloads a nivel aplicaciónCifrado de payload (JWE/JOSE o esquema propio con AEAD) cuando TLS no bastaCifrar “por si acaso”; no definir AAD; no versionar formato
Integridad extremo a extremoFirmas de mensajes a nivel dominio (cliente firma, servidor verifica)Confiar en TLS como E2E; no incluir contexto (audiencia, nonce, versión)

Tokens en la práctica: JWT vs PASETO y cuándo usarlos

Decisión 1: ¿token auto-contenido o sesión opaca?

  • Sesión opaca (cookie de sesión o bearer opaco): el servidor guarda estado (o lo delega a un store). Ventaja: revocación inmediata, tamaño pequeño, menos riesgo de exposición de claims. Ideal para web tradicional.
  • Token auto-contenido (JWT/PASETO): el token lleva claims firmados (y a veces cifrados). Ventaja: validación local en microservicios, menos dependencia de store. Ideal para APIs distribuidas cuando necesitas validación sin llamada central.

Regla práctica: si necesitas revocación fuerte y simple, prefiere sesión opaca. Si necesitas validación distribuida y aceptas revocación por expiración/rotación, considera tokens auto-contenidos.

Decisión 2: JWT o PASETO

  • JWT: estándar ubicuo. Útil cuando necesitas interoperabilidad amplia (gateways, proveedores, librerías corporativas). Requiere disciplina: fijar algoritmo, validar claims, evitar configuraciones “flexibles”.
  • PASETO: diseñado para reducir ambigüedades. Menos “footguns” (por ejemplo, evita el campo alg negociable). Útil cuando controlas emisor y consumidores y quieres una opción más opinada.

Decisión práctica: si tu ecosistema ya está montado sobre JWT (OIDC, API gateways), usa JWT pero con un perfil estricto. Si estás diseñando desde cero y controlas clientes/servicios, PASETO puede simplificar.

Guía paso a paso: perfil mínimo seguro para tokens firmados (JWT/PASETO)

  1. Define el propósito del token: acceso a API (autorización) vs identidad (autenticación). No mezcles: un token de acceso no debería ser “prueba de login” para UI.
  2. Fija audiencia y emisor: define valores exactos para iss y aud (o equivalentes) y valida ambos.
  3. Expiración corta: define exp corto (p.ej. 5–15 min) y usa refresh tokens o reautenticación según riesgo.
  4. Incluye identificador único: jti para trazabilidad y, si necesitas revocación selectiva, para listas de revocación.
  5. Valida el “tiempo” con tolerancia: nbf/iat con un pequeño clock skew.
  6. Versiona claims: añade ver o token_version para migraciones.
  7. Autoriza por scopes/roles explícitos: evita inferir permisos por email/dominio. Documenta scopes y su significado.
  8. Rotación de claves: usa kid (o equivalente) y un endpoint JWKS si aplica; define ventana de convivencia de claves.

Ejemplo de claims típicos para un token de acceso:

{  "iss": "https://auth.ejemplo.com",  "aud": "api://payments",  "sub": "user_123",  "scope": "payments:read payments:write",  "exp": 1735689600,  "iat": 1735689000,  "jti": "b7f1...",  "ver": 2}

Antipatrón: JWT en localStorage para web

En navegadores, guardar tokens bearer en localStorage o sessionStorage aumenta el impacto de XSS (exfiltración directa). Para web, suele ser preferible cookie HttpOnly (no accesible desde JS) y controles CSRF adecuados.

Continúa en nuestra aplicación.
  • Escuche el audio con la pantalla apagada.
  • Obtenga un certificado al finalizar.
  • ¡Más de 5000 cursos para que explores!
O continúa leyendo más abajo...
Download App

Descargar la aplicación

Cookies seguras y sesiones web

Checklist de cookie de sesión

  • HttpOnly: evita lectura por JavaScript.
  • Secure: solo por HTTPS.
  • SameSite: Lax por defecto; Strict si tu UX lo permite; None solo si necesitas third-party y siempre con Secure.
  • Path/Domain mínimos: restringe alcance.
  • Rotación de sesión: al login, elevación de privilegios o cambio de credenciales.

Diseño recomendado: cookie de sesión opaca (ID aleatorio) + estado en servidor (o store). Si necesitas “stateless”, evalúa cuidadosamente el impacto de revocación y exposición de claims.

CSRF: cuándo aplica y cómo mitigarlo sin confusión

CSRF es relevante cuando el navegador envía credenciales automáticamente (cookies). Si usas cookies para autenticar, necesitas mitigación CSRF. Si usas Authorization: Bearer y el token no se envía automáticamente, CSRF suele ser menos relevante (pero XSS sigue siendo crítico).

Mitigación práctica por capas:

  • SameSite=Lax reduce muchos CSRF “clásicos”.
  • Token CSRF para acciones sensibles o cuando SameSite no cubre tu caso (p.ej. flujos cross-site necesarios).
  • Validación de Origin como control adicional (no único).

Guía paso a paso: patrón CSRF con doble submit (cuando no puedes usar estado servidor)

  1. Servidor emite cookie csrf_token (no HttpOnly) con valor aleatorio.
  2. Frontend lee csrf_token y lo envía en header X-CSRF-Token en requests mutantes (POST/PUT/PATCH/DELETE).
  3. Servidor valida que cookie y header coinciden y que la sesión es válida.
  4. Opcional: ata el token a sesión mediante HMAC o incluye un identificador de sesión en el token para evitar reutilización entre sesiones.

Nota de diseño: si ya tienes estado de sesión en servidor, un token CSRF almacenado en servidor (sin depender de doble submit) suele ser más simple de razonar.

Cifrado de payloads a nivel aplicación: cuándo TLS no basta

TLS protege en tránsito entre dos puntos. A veces necesitas protección adicional: intermediarios (proxies, gateways), almacenamiento en colas/logs, o requisitos de “solo el destinatario final puede leer” (confidencialidad end-to-end a nivel aplicación).

Casos típicos donde sí tiene sentido

  • Mensajes que pasan por sistemas intermedios no confiables (colas, buses, integraciones B2B).
  • Datos altamente sensibles que podrían terminar en logs/observabilidad.
  • Arquitecturas donde un gateway termina TLS pero no debe ver el contenido.

Decisiones de diseño para cifrado de payload

  • Define el formato: versiona el sobre (envelope) y especifica campos obligatorios.
  • Incluye AAD: ata el cifrado a contexto (ruta, método, id de mensaje, audiencia) para evitar replays o confusión de destino.
  • Gestión de claves por destinatario: una clave por servicio/tenant/usuario según el modelo; documenta rotación y compatibilidad.
  • Errores uniformes: no filtrar detalles de validación/descifrado al atacante.

Ejemplo de “sobre” (envelope) versionado para un payload cifrado:

{  "v": 1,  "kid": "svc-payments-2026-01",  "alg": "AEAD",  "nonce": "...",  "aad": {"aud":"payments","msg_id":"..."},  "ciphertext": "..."}

Firmas de webhooks: integridad, autenticidad y anti-replay

Un webhook es una petición entrante desde un tercero. Tu objetivo es verificar que el emisor legítimo lo envió y que el contenido no fue modificado. TLS ayuda, pero no sustituye una firma a nivel mensaje (especialmente si hay reintentos, proxies o múltiples rutas).

Patrón recomendado (HMAC) para webhooks

  • Proveedor y consumidor comparten un secreto por endpoint/tenant.
  • El proveedor firma una representación canónica del request (timestamp + método + path + body).
  • El consumidor recalcula y compara en tiempo constante.
  • Se rechazan timestamps fuera de ventana y se deduplican IDs para evitar replay.

Guía paso a paso: verificación de webhook con HMAC

  1. Obtén el raw body exactamente como llegó (antes de parsear JSON). Evita reserializar.
  2. Extrae headers: X-Signature, X-Timestamp, X-Event-Id.
  3. Valida ventana temporal: por ejemplo ±5 minutos.
  4. Construye el string a firmar (canónico): ts + "." + method + "." + path + "." + raw_body.
  5. Recalcula HMAC con el secreto correcto (por tenant o endpoint).
  6. Compara en tiempo constante y rechaza si no coincide.
  7. Anti-replay: guarda event_id por un TTL y rechaza duplicados.

Ejemplo de pseudocódigo:

signed = ts + "." + method + "." + path + "." + rawBodyexpected = HMAC_SHA256(secret, signed)if !constantTimeEquals(expected, providedSig): rejectif abs(now - ts) > 300s: rejectif isReplayed(eventId): rejectprocess()

¿HMAC o firma asimétrica?

  • HMAC: simple y eficiente; requiere compartir secreto (gestión por tenant).
  • Asimétrica: el proveedor firma con privada, tú verificas con pública; útil cuando no quieres secretos compartidos o hay muchos consumidores. Requiere distribución/rotación de claves públicas (p.ej. JWKS).

Integridad extremo a extremo (E2E) a nivel de dominio

“E2E” aquí significa que el cliente final (web/móvil) produce una prueba criptográfica sobre datos de negocio, y el servidor verifica que esos datos no fueron alterados entre la captura y el procesamiento, incluso si hay componentes intermedios.

Ejemplos donde aporta valor

  • Órdenes de pago: el cliente firma importe, moneda, destinatario y un nonce.
  • Consentimientos: el cliente firma el texto/versión del consentimiento y la marca temporal.
  • Telemetría sensible: el dispositivo firma mediciones para detectar manipulación.

Decisiones clave

  • Qué se firma: incluye campos críticos y contexto (audiencia, versión del esquema, nonce, timestamp).
  • Prevención de replay: nonce o contador por sesión/dispositivo.
  • Identidad de clave: cómo asocias la clave pública al usuario/dispositivo (registro, attestation opcional, rotación).

Ejemplo de estructura firmada (canónica) para una orden:

{  "schema": "payment_order/v3",  "aud": "api://payments",  "user_id": "user_123",  "device_id": "dev_456",  "nonce": "n-789",  "ts": 1735689000,  "amount": "125.00",  "currency": "EUR",  "beneficiary": "acct_..."}

Consideraciones móviles: almacenamiento seguro y datos locales

Keystore/Keychain: qué guardar y qué no

  • Guardar: claves privadas del dispositivo, secretos de largo plazo (si el modelo lo requiere), material para desbloquear almacenamiento cifrado, tokens de refresh (según riesgo y políticas).
  • No guardar: tokens de acceso de larga duración sin protección adicional; secretos compartidos globales embebidos en la app; claves “maestras” iguales para todos los usuarios.

Recomendación práctica: usa el almacén seguro del SO (Android Keystore / iOS Keychain) para generar y custodiar claves no exportables cuando sea posible. Para datos locales, cifra con una clave derivada/protegida por el almacén seguro y aplica controles de bloqueo (biometría/PIN) según sensibilidad.

Protección de datos locales: patrón de “sobre” para almacenamiento

Para bases locales (SQLite), archivos o cachés:

  1. Clasifica datos: PII, tokens, datos de negocio, caché no sensible.
  2. Define política de persistencia: qué se puede cachear, TTL, borrado al logout.
  3. Cifra en reposo lo sensible: usa un DEK (data encryption key) por usuario o por instalación.
  4. Protege el DEK: envuélvelo (wrap) con una clave del Keystore/Keychain o usa claves no exportables para operar.
  5. Integridad: usa formatos que detecten manipulación (AEAD) y valida antes de usar.

Sincronización segura móvil ↔ backend

Problemas típicos: conflictos, reintentos, offline, y riesgo de replay. Diseño recomendado:

  • Identificadores idempotentes por operación (op_id) para reintentos seguros.
  • Versionado de registros (ETag/versión) para detectar conflictos.
  • Firmas por operación (opcional) si necesitas integridad E2E: el cliente firma el “delta” con nonce y versión.
  • Minimiza datos en tránsito: envía solo cambios, no dumps completos.

APIs: autenticación y autorización sin reinventar criptografía

Separar conceptos: OAuth/OIDC vs mecanismos criptográficos

  • OAuth 2.0: marco de autorización delegada (quién puede hacer qué). Define roles (resource owner, client, authorization server, resource server) y flujos (authorization code, client credentials, etc.).
  • OpenID Connect (OIDC): capa de identidad sobre OAuth (quién es el usuario), con id_token y endpoints estándar.
  • Mecanismos criptográficos: firmas de tokens, validación de claims, intercambio de claves, rotación, etc. Son “cómo se implementa” la seguridad del marco.

Regla práctica: adopta OAuth/OIDC para el modelo y flujos; usa tokens firmados y validación estricta para la parte criptográfica. No inventes un “mini-OAuth” casero.

Flujos de integración típicos (con decisiones de diseño)

1) SPA + API (usuario final)

  • Recomendación: Authorization Code + PKCE.
  • Token de acceso: corto, para API.
  • Refresh token: si aplica, guárdalo con máxima protección (en web, preferir rotación y almacenamiento seguro vía cookie HttpOnly en backend-for-frontend).
  • Validaciones en API: iss, aud, exp, scopes, y kid contra JWKS.

2) App móvil + API

  • Recomendación: Authorization Code + PKCE con navegador del sistema (no webview embebida).
  • Almacenamiento: refresh token en Keychain/Keystore; access token en memoria o almacenamiento efímero.
  • Defensa adicional: atar sesión a dispositivo (device_id), detección de jailbreak/root según política, y rotación de refresh tokens.

3) Servicio a servicio (microservicios)

  • Recomendación: Client Credentials (OAuth) o mTLS + autorización por claims.
  • Tokens: audiencias específicas por servicio; scopes mínimos.
  • Rotación: claves y credenciales con caducidad y automatización.

Cómo documentar requisitos criptográficos para equipos (plantilla utilizable)

La documentación efectiva reduce errores de implementación. Debe ser verificable (tests), versionada y con ejemplos. Puedes alojarla en plataformas de aprendizaje internas (p.ej., módulos en LMS corporativo) y en el repositorio (README/ADR).

Plantilla de especificación (para un endpoint o integración)

SecciónQué incluir
ObjetivoQué protege: sesión, integridad de evento, confidencialidad de payload, E2E, etc.
ActoresCliente, API, auth server, terceros (webhooks), intermediarios.
CredencialesTipo: cookie de sesión, access token, refresh token, secreto HMAC por tenant, clave pública, etc.
FormatoHeaders, claims, campos firmados/cifrados, canonicalización, versión del sobre.
ValidacionesLista exacta: iss/aud/exp/scope; timestamp window; anti-replay; constant-time compare.
RotaciónCómo cambia kid, ventanas de convivencia, manejo de claves antiguas.
ErroresCódigos y mensajes (no filtrar detalles), métricas y logging seguro.
EjemplosRequests/responses completos, casos válidos e inválidos.
TestsCasos de prueba: token expirado, aud incorrecta, firma inválida, replay, clock skew.

Ejemplo de requisitos para un webhook (extracto listo para pegar)

  • Headers obligatorios: X-Signature (hex/base64), X-Timestamp (unix seconds), X-Event-Id (UUID).
  • String a firmar: {ts}.{method}.{path}.{raw_body} (UTF-8).
  • Algoritmo: HMAC-SHA-256.
  • Ventana temporal: 300s.
  • Anti-replay: rechazar X-Event-Id repetidos durante 24h.
  • Comparación: tiempo constante.
  • Respuesta ante fallo: HTTP 401 sin detalles; log interno con correlation id.

Ahora responde el ejercicio sobre el contenido:

En una integración de webhooks, ¿qué conjunto de verificaciones ayuda a garantizar integridad, autenticidad y protección anti-replay del evento recibido?

¡Tienes razón! Felicitaciones, ahora pasa a la página siguiente.

¡Tú error! Inténtalo de nuevo.

La verificación robusta de webhooks incluye firma a nivel mensaje sobre datos canónicos (p.ej., timestamp+método+path+raw body), comparación en tiempo constante, validación de ventana temporal y deduplicación de un ID para mitigar replay.

Siguiente capítulo

Criptografía en datos en reposo: bases de datos, archivos y backups

Arrow Right Icon
Portada de libro electrónico gratuitaCriptografía aplicada para profesionales: qué usar, cuándo y por qué.
77%

Criptografía aplicada para profesionales: qué usar, cuándo y por qué.

Nuevo curso

13 páginas

Descarga la aplicación para obtener una certificación gratuita y escuchar cursos en segundo plano, incluso con la pantalla apagada.