Come funziona un sistema di ticket
Un sistema di ticket - quello che vedi ai festival - funziona così: quando un utente paga per il suo biglietto, una riga viene aggiunta al database con una colonna chiamata is_scanned
, il cui valore predefinito è impostato su false.
Non appena una guardia al festival scansiona il codice a barre (contenente un ID e un hash univoco) con il proprio dispositivo, viene inviata una richiesta al database per verificare se:
- l'utente che corrisponde all'ID e all'hash ha pagato e
- se il valore della colonna
is_scanned
è ancora impostato sufalse
.
Se entrambe le condizioni sono soddisfatte, imposta il valore is_scanned
su true
, per impedire a qualcun altro di copiare il ticket / codice a barre di entrare.
Il problema di vulnerabilità
Il problema qui è il tempo che intercorre tra la richiesta inviata dal dispositivo di scansione e il valore is_scanned
viene modificato da false
a true
.
Considera questa scena rio: Alice ha un biglietto valido che ha pagato, ma poi lascia che Eve copi il suo codice a barre e cambia il nome visibile sul biglietto falso da Alice ad Eve. Quindi ora abbiamo due biglietti. Uno valido e uno fraudolento, ma entrambi hanno lo stesso codice a barre, l'unica differenza è il nome.
E se il biglietto di Alice ed Eve fosse scansionato esattamente nello stesso momento in cui entrano al festival ? Il sistema di ticket non commutava is_scanned
a true
in tempo per assicurarsi che Eve non potesse entrare con lo stesso codice a barre di Alice. Ciò fa sì che entrambi i ticket (quello valido e quello fraudolento) vengano mostrati come "validi" alle guardie.
Possibili soluzioni
Naturalmente, questo tipo di exploit dipende davvero da molti fortuna, e sebbene sia possibile in teoria ... in uno scenario reale, questo probabilmente fallirebbe.
Tuttavia, come possiamo sconfiggere questo tipo di exploit anche in teoria?
Identificazione
Ho già preso in considerazione questo exploit utilizzando il seguente metodo: Quando un codice a barre viene scansionato, visualizzo non solo se il biglietto è valido (soddisfa le condizioni indicate in precedenza), ma anche il nome nel database. Se il nome non corrisponde a quello sul biglietto, sappiamo che il biglietto è manipolato in qualche modo. Inoltre, se il nome che compare sul dispositivo di scansione, non corrisponde al nome sull'ID (che tutti devono comunque mostrare per provare l'età), anche l'immissione non è consentita.
L'unico modo per aggirare questa soluzione è la frode di identità e, ovviamente, il controllo va oltre la responsabilità del sistema di ticket.
Ritardo
Un altro modo per risolvere questo problema, in teoria, è aggiungere un tempo casuale di ritardo tra ogni richiesta effettuata al database / API di convalida. In questo modo, nessuno sarebbe in grado di scansionare il proprio biglietto contemporaneamente ... perché il tempo di convalida viene ritardato ogni volta con una quantità casuale di millisecondi.
Non sono un fan di questo , perché:
- rende tutto più lento all'ingresso
- non è efficace se non è sufficientemente ritardato. Perché se il database impiega 50 ms per aggiornare
is_scanned
dafalse
atrue
, l'unica soluzione sarebbe ritardarlo con un intervallo minimo 50 ms ogni volta.
Altre soluzioni?
Quali altre soluzioni pensi per risolvere questo exploit?