Race condition in una rotta API di Next.js

Un coupon monouso dovrebbe funzionare una sola volta.

Ma in questo scenario, trenta persone possono usarlo esattamente nello stesso momento.

Questo accade a causa di una race condition di tipo Time-of-Check Time-of-Use (TOCTOU).

L'errore si verifica in due passaggi:

  • Passaggio 1: Il server legge il database per controllare il numero di utilizzi.
  • Passaggio 2: Il server invia un secondo comando per incrementare quel conteggio.

Se invii molte richieste contemporaneamente, il server le gestisce tutte nel mezzo di questi due passaggi.

Molte richieste leggono il conteggio mentre è ancora pari a zero. Superano tutte il controllo. Applicano tutte lo sconto. Incrementano tutte il contatore.

Il risultato? Un coupon destinato a una sola persona viene utilizzato trenta volte.

È facile non accorgersene durante le code review. La logica sembra perfetta quando la leggi riga per riga. Il difetto emerge solo quando si considerano velocità e concorrenza.

Come risolvere:

Smetti di usare comandi di lettura e scrittura separati. Usa invece un'unica operazione atomica.

In Prisma, puoi usare updateMany con una condizione nella clausola WHERE:

• Il database controlla la condizione ed esegue l'aggiornamento in un unico movimento. • Se il conteggio ha già raggiunto il limite, l'aggiornamento fallisce immediatamente. • Nessun'altra richiesta può inserirsi tra il controllo e la scrittura.

Un'altra opzione è l'uso di una transazione del database. Questa blocca i dati in modo che nessun'altra richiesta possa toccarli finché non hai terminato.

Per SQLite, il singolo comando di aggiornamento è il metodo più affidabile.

Chiediti sempre: cosa succede se due richieste colpiscono questa logica nello stesso millisecondo?

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