Seguridad de la integración
Esta sección reúne las prácticas de seguridad que acompañan al flujo de pagos con 3DS. El flujo reparte trabajo entre tu servidor y el navegador del tarjetahabiente, y ese reparto es lo que mantiene tus credenciales y los datos de la tarjeta fuera del alcance de terceros.
Qué vive en tu servidor y qué en el navegador
| En tu servidor | En el navegador |
|---|---|
| La API Key | Recolectar threeDSParams |
| Todas las llamadas a la API de Cubo | El iframe oculto del 3DS Method |
El authenticationToken | El iframe visible del challenge |
Generar y guardar la x-idempotency-key | Consultar tu backend por el estado |
| Decidir si el pago continúa |
La API Key nunca llega al navegador. Esto incluye no ponerla en variables de entorno del build del
frontend: VITE_*, NEXT_PUBLIC_* y equivalentes se empaquetan en el bundle y son públicas.
El authenticationToken tampoco. Es el secreto que autoriza a consultar el resultado de la autenticación. Guárdalo del lado del servidor, asociado al transactionId. Lo único que tu frontend necesita recibir de tu backend tras la solicitud inicial es:
{ "transactionId": "a3f9c2b1-...", "methodURL": "https://acs.banco.com/3ds-method", "threeDSMethodData": "eyJ0aHJlZURTU2VydmVyVHJhb..." }Y, mientras el challenge está en curso, el status y, cuando corresponda, creq y acsURL.
Tu propio endpoint de consulta también es una superficie
Para que el navegador sepa cuándo terminó el challenge, expondrás un endpoint propio que por detrás consulta el resultado 3DS agregando el 3ds-token. Ese endpoint es un proxy a un recurso sensible:
- Verifica pertenencia. Ata la sesión al usuario que inició el pago y rechaza consultas de cualquier otro. Buscar solo por
transactionIdlo convierte en algo consultable por quien conozca o adivine un identificador. - Aplica rate limiting, tanto ahí como en tu endpoint de creación de pagos.
- No propagues el error crudo de la API de Cubo hacia el navegador. Devuelve un mensaje propio y registra el detalle en tu servidor.
Datos de tarjeta
La solicitud de confirmación obliga a reenviar el mismo cuerpo del paso 2, lo que incluye el número de tarjeta y el cvv. Eso te obliga a conservarlos mientras dura el flujo:
- En memoria o en la sesión del servidor, nunca en base de datos.
- Con un tiempo de vida igual al de la ventana de 3DS (10 minutos) y descartados en cuanto el pago se resuelve.
- El
cvvno se persiste en ningún caso, ni siquiera cifrado.
Qué no debe aparecer en tus logs
| Dato | Qué hacer |
|---|---|
X-API-KEY | Redactar por completo. |
cvv | Redactar por completo. |
cardNumber | Dejar solo los últimos 4 dígitos. |
authenticationToken / 3ds-token | Redactar por completo. |
cavv / authenticationValue | Redactar por completo. |
El cavv es el criptograma que prueba la autenticación ante el emisor: trátalo con el mismo cuidado que un token.
Tres descuidos frecuentes:
- Los headers. Es fácil enmascarar el cuerpo y olvidar que la API Key y el
3ds-tokenviajan como header. - Los reportes de errores. Herramientas como Sentry o Datadog capturan la solicitud completa por defecto.
- El
catchgenérico. Unconsole.error(error)sobre un error de cliente HTTP suele incluir la configuración entera de la solicitud, headers incluidos.
La IP del tarjetahabiente, no la de tu servidor
client-ip-address debe llevar la IP pública del comprador, tomada de la conexión entre su navegador y tu servidor. Si estás detrás de un proxy o CDN, léela del header X-Forwarded-For (la primera entrada) y no de la IP de la conexión.
Enviar la IP de tu servidor es peor que no enviar nada: las reglas de riesgo verían todas las transacciones viniendo del mismo origen.
Credenciales
- Una API Key por ambiente. Pruebas y producción nunca comparten configuración ni repositorio.
- Fuera del control de versiones.
- Rotables sin desplegar código, para que rotar ante una sospecha sea barato.
- Acceso acotado: cuantas menos personas y sistemas la tengan, más corta es la lista a revisar si algo pasa.
Antes de salir a producción
Un repaso rápido, agrupado por área, de lo que conviene revisar antes de activar 3DS en producción.
| Área | Qué revisar |
|---|---|
| Credenciales | El bundle del frontend no contiene la API Key ni el authenticationToken. Las credenciales de producción están separadas de las de pruebas y son rotables. |
| Tu backend | Tu endpoint de consulta verifica pertenencia y tiene rate limiting. La x-idempotency-key se genera en el servidor y hay una protección de servidor contra la confirmación duplicada. |
| Datos | El número de tarjeta y el cvv no se persisten. Los logs enmascaran API Key, 3ds-token, cvv, número de tarjeta y cavv. client-ip-address lleva la IP del comprador. |
| Flujo 3DS | Los estados A y D están contemplados. xid lleva el dsTransId de la respuesta terminal. Ante un timeout se consulta el estado de la key en vez de reintentar. |