Condición de carrera en una ruta de API de Next.js

Un cupón de un solo uso solo debería funcionar una vez.

Pero en este escenario, treinta personas pueden usarlo exactamente al mismo tiempo.

Esto sucede debido a una condición de carrera de tipo Time-of-Check Time-of-Use (TOCTOU).

El error ocurre en dos pasos:

  • Paso 1: El servidor lee la base de datos para verificar el recuento de usos.
  • Paso 2: El servidor envía un segundo comando para incrementar ese recuento.

Si envías muchas solicitudes a la vez, el servidor las procesa todas en medio de estos dos pasos.

Muchas solicitudes leen el recuento mientras aún es cero. Todas pasan la verificación. Todas aplican el descuento. Todas incrementan el contador.

¿El resultado? Un cupón destinado a una sola persona se usa treinta veces.

Esto es fácil de pasar por alto durante las revisiones de código. La lógica parece perfecta cuando se lee línea por línea. El fallo solo aparece cuando se tiene en cuenta la velocidad y la concurrencia.

Cómo solucionarlo:

Deja de usar comandos de lectura y escritura por separado. En su lugar, utiliza una única operación atómica.

En Prisma, puedes usar updateMany con una condición en la cláusula WHERE:

• La base de datos verifica la condición y realiza la actualización en un solo movimiento. • Si el recuento ya ha alcanzado el límite, la actualización falla inmediatamente. • Ninguna otra solicitud puede colarse entre la verificación y la escritura.

Otra opción es utilizar una transacción de base de datos. Esto bloquea los datos para que ninguna otra solicitud pueda tocarlos hasta que hayas terminado.

Para SQLite, el comando de actualización única es el método más fiable.

Pregúntate siempre: ¿qué pasa si dos solicitudes llegan a esta lógica en el mismo milisegundo?

Fuente: https://dev.to/oopssec-store/racing-a-nextjs-api-route-coupon-abuse-with-prisma-and-sqlite-3gma