Docs

Políticas de Seguridad Financiera

Principios de seguridad, cadena de validaciones, vectores de ataque y mitigaciones para el flujo de pagos con Stripe Connect.

PublicadoMarzo 2026Equipo de desarrollo, arquitectos

1. Arquitectura de Seguridad

El flujo financiero de Nvito sigue 7 principios fundamentales:

PrincipioImplementación
Zero-trust en metadataNunca confiar en datos de metadata de Stripe. Siempre verificar contra BD
IdempotenciaToda operación financiera es idempotente (doble ejecución = mismo resultado)
Transacciones atómicasTodo cambio financiero ocurre en una sola transacción Prisma
Menor privilegioEndpoints de Connect solo para admin. Pagos públicos con rate limiting
Sin flujo legacyNo existe camino donde dinero pueda caer en la cuenta de Nvito
Validación server-sideTodos los límites se validan en el backend. El frontend solo muestra
Auditoría completaToda transacción registrada con stripePaymentIntentId, applicationFeeAmount

2. Cadena de Validaciones

Cada contribución pasa por 6 validaciones obligatorias antes de llegar a Stripe:

ValidaciónDóndeRechaza si
Evento ACTIVEBackendEvento en DRAFT, COMPLETED o CANCELLED
cashFundEnabledBackendSobre de Regalo desactivado
Cuenta Connect verificadaBackendNo existe o chargesEnabled = false
Límite por contribuciónBackend + Clientamount > cashFundMaxContribution
Límite del fondoBackend + ClientcashFundCurrent + amount > cashFundMaxGoal
Nombre del pagadorBackend + ClientpayerName vacío

Doble validación

Los límites se validan tanto en el cliente (UX inmediata) como en el backend (seguridad). El frontend valida en PESOS, el backend en CENTAVOS.


3. Flujo de Dinero

Desglose de Comisiones

ConceptoPorcentajeSobre $1,000 MXN
Stripe México (tarjeta)~3.6% + $3 MXN~$39
Comisión Nvito (configurable)10-15%$100-$150
Anfitrión recibe~82-87%$811-$861

La application_fee_amount se calcula en el backend a partir de giftRegistry.cashFundFeePercent. El frontend NO puede modificarla.


4. Vectores de Ataque y Mitigaciones

4.1 Inyección de stripeAccountId

Detalle
RiesgoDinero va a cuenta equivocada
MitigaciónEl webhook usa payment.stripeConnectedAccountId de BD, NO de metadata de Stripe

4.2 PaymentIntent sin cuenta Connect

Detalle
RiesgoDinero cae en cuenta Nvito
MitigacióncreateCashFundIntent SIEMPRE requiere getVerifiedAccountForEvent(). Sin cuenta verificada = ValidationException. No existe flujo legacy

4.3 Doble incremento de cashFundCurrent

Detalle
RiesgoConteo inflado
MitigaciónWebhook verifica payment.status !== SUCCEEDED antes de incrementar. Prisma.increment es atómico

4.4 Manipulación de application_fee

Detalle
RiesgoNvito no recibe comisión
MitigaciónLa fee se calcula en el BACKEND. El frontend no puede modificarla. Stripe la cobra automáticamente

4.5 Contribución que excede límite (race condition)

Detalle
RiesgoFondo excede meta
MitigacióncashFundMaxGoal es un soft limit validado pre-intent. La validación no usa lock transaccional, por lo que contribuciones simultáneas podrían exceder marginalmente. Aceptable para MVP

4.6 Webhook falsificado

Detalle
RiesgoProcesamiento de pagos falsos
MitigaciónFirma validada con constructWebhookEvent(). Connect usa secret separado (STRIPE_CONNECT_WEBHOOK_SECRET)

4.7 Chargebacks y disputas

Detalle
RiesgoPérdida de dinero e inconsistencia de datos
MitigaciónHandler handleDisputeCreated decrementa cashFundCurrent atómicamente y marca Payment como REFUNDED. Las disputas se manejan en la cuenta del organizador, no de Nvito

4.8 Admin resetea cashFundCurrent

Detalle
RiesgoPérdida de integridad financiera
Mitigacióngift-registry.service.ts hace delete data.cashFundCurrent en el update — imposible modificar via DTO. Solo webhook y confirm pueden modificarlo

4.9 Desactivación con fondos recaudados

Detalle
RiesgoPérdida de datos financieros
MitigaciónhandleToggle solo envía { cashFundEnabled: false }. NO resetea cashFundCurrent, cashFundGoal ni la cuenta Connect. Confirmación obligatoria si hay fondos

4.10 Stripe desactiva la cuenta

Detalle
RiesgoInvitados ven botón de pago roto
MitigaciónWebhook account.updated detecta estado DISABLED → desactiva cashFundEnabled automáticamente + log de alerta

4.11 Eliminación de evento con fondos

Detalle
RiesgoCuenta Connect huérfana, pagos perdidos
MitigaciónEl backend bloquea eliminación si hay pagos PROCESSING. Marca cuenta Connect como COMPLETED antes del soft delete

5. Webhooks Procesados

EventoHandlerAcciónIdempotente
payment_intent.succeededhandlePaymentIntentSucceededSUCCEEDED + cashFundCurrent++Sí (verifica status previo)
payment_intent.payment_failedhandlePaymentIntentFailedFAILED
charge.dispute.createdhandleDisputeCreatedREFUNDED + cashFundCurrent--Sí (verifica status previo)
charge.refundedhandleChargeRefundedREFUNDED + cashFundCurrent--Sí (verifica status previo)
account.updatedhandleAccountUpdatedSync status + auto-disable

6. Protección de Datos Personales

DatoRetenciónAnonimización
legalNameHasta 6 meses post-eventoSe establece a null
emailHasta 6 meses post-eventoSe establece a null
rfcHasta 6 meses post-eventoSe establece a null
stripeAccountIdPermanenteSe mantiene como referencia

Datos que Nvito NUNCA almacena

  • Números de tarjeta de crédito (PCI compliance via Stripe)
  • CLABE bancaria (solo en Stripe)
  • Documentos de identidad (solo en Stripe)

7. Procedimiento de Respuesta ante Disputas

  1. Stripe notifica via webhook charge.dispute.created
  2. El sistema decrementa cashFundCurrent y marca el Payment como REFUNDED
  3. La disputa se maneja en la cuenta Connect del organizador
  4. El organizador tiene 7-21 días para responder con evidencia
  5. Nvito NO interviene financieramente — la disputa es entre invitado y organizador

Importante

Con Stripe Connect Express, Nvito actúa como intermediario tecnológico. Las disputas financieras son responsabilidad del organizador (titular de la cuenta Connect).


8. Ciclo de Vida de la Cuenta Connect

Cambio de Beneficiario

Solo un Super Admin puede ejecutar el cambio:

  1. Verifica que no hay pagos PROCESSING
  2. Archiva la cuenta actual (status → ARCHIVED)
  3. Los pagos anteriores quedan vinculados a la cuenta archivada
  4. Se puede crear una nueva cuenta Connect para el mismo evento

9. Archivos Clave

ArchivoResponsabilidad
stripe-connect.service.tsGestión cuentas (crear, sync, archivar, verificar)
stripe-connect.controller.tsEndpoints admin + archivo Super Admin
payments.service.tscreateCashFundIntent con validaciones
stripe-webhook.service.tsHandlers de todos los eventos (payment, dispute, refund)
payments-webhook.controller.tsEndpoint webhook Stripe + Connect
gift-registry.service.tsProtección cashFundCurrent + validación meta vs recaudado
event-mutation.service.tsProtección eliminación evento con pagos
Esta pagina fue util?