La validazione raramente fallisce perché l’aritmetica è difficile. Quando validi un numero di carta di credito in un’applicazione reale, i fallimenti derivano dall’eseguire i controlli nell’ordine sbagliato, dal fidarsi del browser e dal segnalare ogni tipo di problema con lo stesso messaggio inutile. Le regole in sé richiedono poche righe per essere espresse; la disciplina sta nel metterle in sequenza e nel decidere cosa significa ogni fallimento.
Questo articolo copre a cosa serve la validazione, l’ordine che evita risultati privi di senso, il confine tra verificare un valore e autorizzare un pagamento, e i test che intercettano difetti reali anziché confermare ciò che già credi.
A cosa serve davvero la validazione
Lo scopo di validare un numero di carta è rifiutare input che non può in alcun modo funzionare, e farlo prima che accada qualcosa di costoso. Risparmia all’utente l’invio di un modulo che fallirà, tiene i valori malformati fuori dai tuoi stessi registri e riduce il traffico inutile verso un gateway di pagamento.
Vale la pena essere espliciti su a cosa non serve. Non è un controllo antifrode, non è prova di titolarità e non è un sostituto dell’autorizzazione. Un numero che supera ogni regola applicabile localmente può comunque essere rifiutato dall’emittente, e un numero che rifiuti può appartenere a un cliente autentico se le tue regole sono sbagliate. Quest’ultimo punto è quello che costa denaro, perché rifiutare una carta valida è invisibile a te ed esasperante per il cliente.
Quali controlli dovrebbero essere eseguiti per primi?
L’ordine determina se i tuoi errori hanno senso. La sequenza che si comporta bene parte dal generale e si restringe:
- Presenza. Un campo vuoto non è un numero malformato, e dirlo evita un messaggio confuso.
- Set di caratteri. Decidi quali separatori tolleri, rimuovili e rifiuta tutto il resto. Fallo prima della lunghezza, così un numero incollato con spazi non viene giudicato sul suo conteggio grezzo di caratteri.
- Lunghezza. Confronta con l’intervallo della rete rilevata anziché con un unico valore universale; le lunghezze valide variano tra reti e prodotti.
- Prefisso. Una volta che la lunghezza è plausibile, controlla che le cifre iniziali appartengano a una rete che intendi davvero supportare.
- Somma di controllo. Calcola il controllo modulo dieci descritto nella guida all’algoritmo di Luhn e confrontalo con la cifra finale.
Eseguire la somma di controllo per prima produce il comportamento peggiore, perché la procedura restituirà tranquillamente un risultato per un frammento di tre cifre o per una stringa contenente lettere, e l’utente riceverà poi un messaggio su un controllo fallito su cui non può agire.
La validazione lato client è sufficiente?
No, e il motivo non è soltanto che JavaScript può essere disabilitato. Un controllo lato browser è una cortesia verso chi digita: dà un riscontro immediato e risparmia un giro di rete. Non è un controllo di sicurezza, perché qualsiasi cosa giri nel browser è sotto il controllo dell’utente, e perché il codice client non è l’unico modo in cui i valori raggiungono il tuo sistema.
Il server deve ripetere la stessa sequenza, in modo indipendente. Se i due discordano — uno accetta ciò che l’altro rifiuta — allora hai trovato o un bug o una regola non documentata, e verrà a galla prima o poi come un ticket di assistenza su una carta che funziona su una pagina e non su un’altra.
C’è anche un terzo livello: il fornitore di pagamenti esegue i propri controlli e rifiuterà valori che il tuo codice ha accettato. Questo è normale, ed è il motivo per cui il tuo flusso deve gestire con garbo un errore del gateway anziché presumere che un numero localmente valido venga elaborato.
Cosa dovrebbe dire un messaggio di errore?
Problemi diversi richiedono risposte diverse, e un campo che dice solo che il numero di carta non è valido lascia l’utente a indovinare.
Un insieme utile copre le situazioni realistiche. Vuoto è un invito, non un errore. Troppo corto o troppo lungo è un conteggio, formulato nei termini dell’inserimento dell’utente. Un carattere non supportato dovrebbe dire quali caratteri sono accettati, perché l’utente spesso non riesce a distinguere una lettera vagante da un separatore che tolleri. Una lunghezza che non corrisponde ad alcuna rete supportata è di solito il segno che è stata rilevata la rete sbagliata, non che l’utente abbia inventato una carta. Una somma di controllo fallita è l’unico caso in cui il messaggio onesto è che il numero sembra digitato male, il che suggerisce una singola cifra errata senza affermare che la carta sia cattiva.
Nota che nessuno di questi messaggi dovrebbe affermare che la carta è falsa. Il modulo non lo sa, e dire a un cliente reale che la sua carta non è autentica è un’esperienza di assistenza memorabile.
Un controllo superato non è un pagamento approvato
Questa è la distinzione che tiene le squadre oneste. Tutto ciò descritto sopra è un’affermazione sulla forma di una stringa. L’approvazione viene solo da una richiesta di autorizzazione all’emittente, e dipende dal conto, dal saldo, dalle regole di rischio dell’emittente stesso e da qualsiasi autenticazione venga chiesta al cliente.
Quindi, quando un ambiente di test produce una carta che soddisfa ogni controllo locale, la descrizione accurata è che il valore è strutturalmente valido e mai emesso. Supererà la tua validazione e sarà rifiutato da qualsiasi gateway reale, che è precisamente ciò che lo rende sicuro per testare la validazione stessa.
La stessa logica vale nel verso opposto. Un numero che fallisce la tua somma di controllo è input malformato; un numero che la supera ed è comunque rifiutato è un esito commerciale. Unire i due in un unico percorso di errore rende entrambi più difficili da correggere.
Per gli sviluppatori: ordine, normalizzazione e i test che contano
Tre abitudini fanno reggere questo codice nel tempo.
Metti la sequenza in un unico posto. Lunghezza, caratteri, prefisso e somma di controllo dovrebbero risiedere in un’unica routine con un ordine definito, richiamata sia dal client sia dal server. La logica duplicata è dove i due livelli si allontanano silenziosamente.
Normalizza una volta e conserva l’originale. Rimuovi i separatori, mantieni le cifre come stringa e non lasciare mai che un tipo numerico tocchi il valore. Conserva la forma ripulita per il confronto e, se ti serve per la visualizzazione, anche la forma raggruppata — ma deriva una dall’altra anziché memorizzare due copie indipendenti che possono discordare.
Poi testa i fallimenti, non il successo. I casi che trovano bug reali sono un numero valido con una cifra cambiata, un numero contenente una lettera, un numero con uno zero iniziale, un invio vuoto, un valore di lunghezza massima e un incolla contenente separatori. Per ciascuno, verifica il messaggio specifico che il tuo utente riceve, non solo che la validazione sia fallita.
Vale anche la pena di verificare dove può viaggiare il valore. Le funzioni di validazione tendono a essere riutilizzate, e una routine scritta per un modulo viene talvolta chiamata con valori arrivati da una coda o da un’importazione. Quei chiamanti hanno bisogno delle stesse regole applicate, e raramente hanno un utente a cui mostrare un messaggio — il che significa che l’errore deve essere registrato da qualche parte dove un umano lo leggerà.
Infine, tieni d’occhio cosa fa il campo con i dati dopo che sono stati accettati. Le regole di mascheramento, archiviazione e logging sono governate dallo standard del settore delle carte anziché dalle tue preferenze, e le note di conformità riassumono le parti che riguardano un ambiente di test. La guida al formato dettaglia le regole di lunghezza e prefisso citate sopra.
Esercitarsi su numeri generati
Il modo più veloce per controllare un validatore è puntarlo su dati di cui conosci in anticipo il risultato atteso. Il generatore di numeri di carta produce lotti di numeri ben formati per costruzione, quindi qualsiasi rifiuto è o un bug nel validatore o una regola che non intendevi scrivere. Genera un insieme, corrompi deliberatamente una cifra in una copia e conferma che i due vengono classificati diversamente con due messaggi diversi.
Passi successivi
Scrivi l’ordine dei controlli come commento sopra la routine, assicurati che il server lo applichi in modo indipendente e aggiungi una fixture negativa per ogni positiva. Se il tuo modulo raccoglie anche una data o un codice di sicurezza, la checklist del modulo di pagamento elenca i flussi circostanti a cui quei campi appartengono.