Tema representativo de entrevista

Entrevista de Backend: ¿Cómo diseñarías una API con restricción de remitente mediante DPoP?

BackendDifícil
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

Necesitas proteger una API de OAuth contra tokens de acceso copiados de registros o del almacenamiento del cliente. ¿Cómo diseñarías una API con restricción de remitente mediante DPoP, incluyendo verificación, cachés de reproducción, rotación de claves y mecanismos de respaldo?

Planteamiento y alcance

Eres el propietario de una API de OAuth utilizada por clientes móviles y de navegador. Actualmente, el servidor de recursos solo valida tokens de acceso Bearer; una sola filtración en los registros podría permitir que un atacante reproduzca solicitudes mientras el token sea válido. Diseña un esquema DPoP (Demonstrating Proof-of-Possession), que incluya el servidor de autorización, el cliente, el servidor de recursos y el comportamiento cuando DPoP no esté disponible.

Esta es una pregunta de arquitectura de seguridad de backend, no un cuestionario sobre configuración de proveedores. La RFC 9449 vincula un token de acceso a una clave pública del cliente y requiere que cada llamada incluya una prueba vinculada al método HTTP y al URI. La RFC 9700 añade guías de seguridad actuales de OAuth, como evitar flujos débiles y utilizar PKCE.

Qué está evaluando el entrevistador

Una respuesta sólida comienza con el modo de fallo de los tokens Bearer: cualquiera que tenga la cadena de texto puede usarla, por lo que un token robado es indistinguible de una solicitud legítima. Luego, describe un flujo de extremo a extremo: el cliente genera una clave, el endpoint de tokens verifica una prueba DPoP y vincula la clave pública, y el servidor de recursos comprueba la firma, el método, el URI, el hash del token y la ventana de tiempo.

El entrevistador también espera un plan para la reproducción de jti, nonces del servidor, pérdida de claves, reescritura de URI por proxies, tokens de actualización (refresh tokens), clientes antiguos y telemetría. Decir simplemente «firmar el JWT» es insuficiente: una firma de JWT normal demuestra la integridad del emisor, pero no que el emisor de la llamada aún posea la clave privada utilizada durante la emisión.

Preguntas para aclarar primero

Cliente y modelo de amenazas

Confirma si el cliente es una SPA de navegador, una aplicación móvil nativa o una aplicación de servidor. El ciclo de vida varía en función de si la clave privada puede residir en un almacenamiento respaldado por hardware y de si cada instalación obtiene su propia clave. Pregunta si el atacante puede leer registros, proxies, almacenamiento del navegador o archivos del dispositivo, y si puede interceptar solicitudes en tiempo real.

Límite del servidor de recursos

Confirma los gateways, la terminación TLS y el reenvío interno. El htu de DPoP debe coincidir con la semántica del URI que verifica el servidor de recursos. Si un gateway reescribe rutas, define la canonicalización y encabezados de reenvío confiables; no permitas que un cliente firme una dirección mientras el backend verifica otra.

Restricciones de disponibilidad y migración

Pregunta si los clientes Bearer heredados deben seguir funcionando, si se acepta un breve periodo de coexistencia (dual-stack) y si el inicio de sesión y la actualización utilizan el mismo servidor de autorización. Si la regulación o una API de alto valor exige una restricción estricta del remitente, haz que DPoP sea obligatorio. Para recursos de menor riesgo, migra mediante negociación de capacidades y un despliegue medido.

Estructura de respuesta de 30 segundos

«Diseñaría DPoP como un protocolo de tres partes. El cliente genera un par de claves por instalación y envía una prueba DPoP de un solo uso durante la solicitud del token. El servidor de autorización la verifica y vincula el cnf.jkt del token de acceso a la clave pública. Cada llamada a la API transporta un JWT DPoP nuevo; el servidor de recursos comprueba su firma, htm, htu, iat, el jti único, ath y el cnf.jkt del token, utilizando un nonce y una ventana de tiempo corta para reducir la reproducción. La pérdida de una clave privada revoca los tokens vinculados. Los clientes heredados obtienen una ruta Bearer por tiempo limitado únicamente para recursos explícitamente de bajo riesgo, mientras que las operaciones de alto valor pasan a DPoP obligatorio».

Solución paso a paso

Paso 1: Crear la clave y vincular la autorización

En la primera ejecución, el cliente genera un par de claves asimétricas y guarda la clave privada en el almacenamiento seguro del dispositivo. Envía la clave pública en el JWK transportado por una prueba DPoP al solicitar un token. El servidor de autorización valida la firma, el tipo y la marca de tiempo de la prueba, y luego vincula los datos de confirmación del token a la huella digital (thumbprint) del JWK de la clave pública. Con un flujo de código de autorización (authorization code), sigue utilizando las directrices de PKCE de la RFC 9700: DPoP demuestra la posesión del token y no reemplaza la protección del código.

Paso 2: Generar una prueba por solicitud

Para cada solicitud, el cliente crea un JWT nuevo que contiene al menos jti, htm, htu y iat, y luego lo firma con la clave privada vinculada. Coloca un hash del token de acceso en ath, lo que permite al servidor de recursos verificar que la prueba apunta a este token y no a otro firmado con la misma clave. La prueba se incluye en el encabezado DPoP, y el token de acceso utiliza el esquema de autorización DPoP en lugar de Bearer.

Paso 3: Verificar en un orden fijo

El servidor de recursos restringe primero los algoritmos y los tipos de JWK, luego verifica la firma del JWT, el formato de la clave, la ventana de tiempo, el método y el URI. Aplica una función hash al token de acceso y compara el resultado con ath; lee cnf.jkt del token y lo compara con la huella digital de la clave de la prueba. Luego comprueba si el jti ya ha aparecido dentro de la ventana actual antes de aplicar la autorización ordinaria de alcance (scope), audiencia y recursos.

Paso 4: Gestionar nonces y reproducción

El servidor puede emitir un nonce para recursos de alto riesgo, requiriendo que el cliente lo incluya en la siguiente prueba. Se requiere deduplicación de jti dentro de la ventana de aceptación. Una caché de un solo nodo funciona para un despliegue pequeño; los servidores de recursos con múltiples instancias necesitan una caché compartida con expiración o deben aceptar explícitamente el riesgo de duplicados en ventanas cortas y registrarlo como un evento de seguridad. La telemetría de rechazos debe distinguir entre expiración, firmas inválidas, discrepancias de huella digital y ausencia de nonce sin exponer material de claves.

Paso 5: Diseñar rotación, revocación y mecanismos de respaldo

Si se pierde un dispositivo, se expone una clave privada o el servidor detecta abuso, revoca los tokens de acceso y actualización asociados con esa huella digital y exige una nueva autorización. La rotación no puede ser un simple reemplazo silencioso en el cliente: la nueva clave pública requiere una nueva vinculación de autorización. Durante la migración, un servidor de recursos puede aceptar ambos esquemas, pero las escrituras de alto valor deben tener una política independiente de DPoP obligatorio para que la compatibilidad nunca se convierta en la opción de seguridad por defecto.

Paso 6: Comparar mTLS con Bearer simple

mTLS sitúa la prueba en la capa de certificados de cliente TLS y se adapta bien a sistemas de servidor a servidor con operaciones de certificados maduras. DPoP opera a nivel de la capa de aplicación y se adapta a clientes móviles y de navegador, pero añade operaciones de prueba, nonce, jti y almacenamiento de claves. Bearer simple es el más fácil de desplegar, pero no puede resistir la reproducción tras la copia de la cadena del token. Elige en función de las capacidades del cliente, la topología de proxies, el cumplimiento normativo y el coste operativo, en lugar de habilitar DPoP a ciegas en todos los endpoints.

Respuesta de ejemplo de alta calidad

Comenzaría con el modelo de amenazas: una filtración en registros, proxies o almacenamiento del cliente puede exponer un token de acceso, tras lo cual un atacante puede llamar a la API durante su periodo de validez. Un tiempo de expiración más corto reduce la ventana, pero no demuestra que el emisor de la llamada sea el cliente original.

El cliente crea un par de claves por instalación y protege la clave privada. Durante el intercambio de authorization-code, exijo PKCE y una prueba DPoP; el servidor de autorización verifica la prueba y vincula el cnf.jkt del token a la clave pública. En el servidor de recursos, verifico la firma de la prueba, htm, htu, iat, jti, ath y el nonce en un orden fijo, luego comparo la huella digital de la clave de la prueba con la vinculación del token. Cualquier discrepancia resulta en no autorizado y se clasifica en las métricas de seguridad.

Almaceno los valores de jti en una caché de deduplicación compartida respaldada por TTL para despliegues de múltiples instancias. Las escrituras de alto riesgo requieren nonce y DPoP. Durante la migración, las lecturas de bajo riesgo pueden ser de doble esquema (dual-stack), pero el plazo límite se vincula a la versión del cliente y al riesgo del recurso. Una clave perdida revoca sus tokens e inicia una nueva autorización; un respaldo en Bearer nunca comparte la ruta de escritura de alto valor. Finalmente, ejecuto pruebas de integración para pruebas falsificadas, reproducción de jti antiguos, cambios de URI, hashes de token incorrectos, nonces expirados y reescrituras de proxy, monitoreando luego la tasa de rechazo, reintentos de nonce y huellas digitales anormales para demostrar que la reproducción se está bloqueando.

Errores comunes

  • Error: Firmar el token de acceso únicamente como un JWT. → Por qué falla: La firma demuestra la integridad del emisor, pero no la posesión de la clave privada del cliente. → Solución: Vincular cnf.jkt y verificar una prueba DPoP nueva en cada solicitud.
  • Error: Reutilizar una misma prueba DPoP. → Por qué falla: Un atacante puede reproducir la solicitud completa porque el jti y las comprobaciones de tiempo no pueden distinguirla. → Solución: Generar un nuevo jti por solicitud y deduplicarlo dentro de la ventana de aceptación, añadiendo un nonce cuando sea necesario.
  • Error: Verificar DPoP únicamente en el gateway mientras los servicios internos confían en un encabezado de usuario no vinculado. → Por qué falla: El reenvío puede perder el método, el URI o la vinculación del token y permitir el paso de una identidad falsificada. → Solución: Pasar un resultado de verificación normalizado a través de un límite confiable y restringir quién puede establecerlo.
  • Error: Recurrir al respaldo de Bearer ante cualquier error de validación. → Por qué falla: Un atacante puede provocar intencionadamente errores de DPoP para alcanzar la ruta más débil. → Solución: Permitir un respaldo por tiempo limitado únicamente para clientes heredados registrados y recursos de bajo riesgo.

Preguntas de seguimiento y respuestas

Pregunta de seguimiento 1: ¿Cómo deduplicas jti entre diferentes regiones?

Elige la consistencia según el riesgo del recurso. Las escrituras de alto valor pueden utilizar un almacén compartido entre regiones y asumir un viaje de ida y vuelta (round trip) adicional; las lecturas de bajo riesgo pueden usar cachés regionales y una ventana corta, registrando duplicados sin sacrificar la disponibilidad. En cualquiera de los dos diseños, incluye la ventana, el comportamiento ante fallos y la tasa de duplicados en el SLO.

Pregunta de seguimiento 2: ¿Qué sucede si un ataque XSS lee la clave privada del navegador?

DPoP no puede reparar un entorno de ejecución del cliente que esté completamente comprometido. Prefiere claves no exportables, una estricta política de seguridad de contenido (CSP), tokens de corta duración y rotación de tokens de actualización; revoca la vinculación cuando la huella digital muestre un comportamiento anormal. Delimita claramente el alcance de la protección: DPoP está orientado a tokens copiados cuando la clave privada no fue copiada, no a todas las formas de toma de control del endpoint.

Pregunta de seguimiento 3: Un proxy modifica el URI. ¿Cómo verificas htu?

Define un mapeo desde el URI canónico externo a la ruta interna, y permite únicamente que un proxy de confianza proporcione el esquema, host y ruta originales autenticados. El servidor de recursos aplica la misma canonicalización antes de la comparación y rechaza los encabezados de reenvío no autenticados o controlados por el cliente. Si no existe un mapeo confiable, finaliza DPoP en el límite del sistema y emite una identidad interna de corta duración en lugar de intentar adivinar el URI original.

Pregunta de seguimiento 4: Los clientes heredados solo pueden enviar Bearer. ¿Se pueden admitir indefinidamente?

La compatibilidad permanente no constituye un diseño de seguridad. Establece una fecha límite de migración según la versión del cliente, el riesgo del usuario y el tipo de recurso; exige DPoP primero para escrituras de alto valor, devuelve un error accionable de actualización y monitoriza el tráfico residual. Mantén una ruta Bearer restringida únicamente cuando una evaluación de riesgos lo justifique y añade vinculación de dispositivo o límites de tasa (rate limits).

Fuentes públicas

Preguntas relacionadas