È prassi comune chiedere a un utente di fornire una password monouso (OTP) per confermare la sua identità tramite l'invio di un SMS. Alcuni casi d'uso per l'OTP via SMS includono:
- Autenticazione a due fattori. Oltre al nome utente e alla password, l'OTP via SMS può essere utilizzato come segnale forte che l'account appartiene alla persona che ha ricevuto l'OTP via SMS.
- Verifica del numero di telefono. Alcuni servizi utilizzano un numero di telefono come identificatore principale dell'utente. In questi servizi, gli utenti possono inserire il proprio numero di telefono e l'OTP ricevuto via SMS per dimostrare la propria identità. A volte viene combinato con un PIN per costituire un'autenticazione a due fattori.
- Recupero dell'account. Quando un utente perde l'accesso al proprio account, deve esistere un modo per recuperarlo. L'invio di un'email all'indirizzo email registrato o di un'OTP via SMS al numero di telefono sono metodi comuni di recupero dell'account.
- Conferma del pagamento: nei sistemi di pagamento, alcune banche o emittenti di carte di credito richiedono un'autenticazione aggiuntiva da parte del pagatore per motivi di sicurezza. A questo scopo viene comunemente utilizzato l'OTP via SMS.
Continua a leggere per scoprire le best practice per la creazione di moduli OTP via SMS per questi casi d'uso.
Elenco di controllo
Per offrire la migliore esperienza utente con l'OTP via SMS, segui questi passaggi:
- Utilizza l'elemento
<input>
con:type="text"
inputmode="numeric"
autocomplete="one-time-code"
- Utilizza
@BOUND_DOMAIN #OTP_CODE
come ultima riga del messaggio SMS OTP. - Utilizza l'API WebOTP.
Utilizzare l'elemento <input>
L'utilizzo di un modulo con un elemento <input>
è la best practice più importante che puoi seguire perché funziona in tutti i browser. Anche se altri suggerimenti di questo post non funzionano in alcuni browser, l'utente potrà comunque inserire e inviare manualmente l'OTP.
<form action="/verify-otp" method="POST">
<input type="text"
inputmode="numeric"
autocomplete="one-time-code"
pattern="\d{6}"
required>
</form>
Di seguito sono riportate alcune idee per garantire che un campo di input ottenga il meglio dalle funzionalità del browser.
type="text"
Poiché i codici OTP sono in genere numeri di cinque o sei cifre, l'utilizzo di
type="number"
per un campo di input potrebbe sembrare intuitivo perché cambia la tastiera
mobile in modo che visualizzi solo i numeri. Questa operazione non è consigliata perché il browser si aspetta che un
campo di input sia un numero numerabile anziché una sequenza di più numeri,
il che può causare un comportamento imprevisto. L'utilizzo di type="number"
fa sì che i pulsanti su e giù
vengano visualizzati accanto al campo di input; la pressione di questi pulsanti
aumenta o diminuisce il numero e potrebbe rimuovere gli zeri iniziali.
Utilizza invece type="text"
. In questo modo, la tastiera mobile non si trasformerà in una tastiera con solo numeri, ma non è un problema perché il suggerimento successivo per l'utilizzo di inputmode="numeric"
svolge questa funzione.
inputmode="numeric"
Utilizza inputmode="numeric"
per impostare la tastiera mobile in modo che visualizzi solo numeri.
Alcuni siti web utilizzano type="tel"
per i campi di input OTP, in quanto
quando è attivo, la tastiera mobile mostra solo i numeri (inclusi *
e #
). Questo hack è stato utilizzato in passato quando inputmode="numeric"
non era ampiamente supportato. Da quando Firefox ha iniziato a supportare
inputmode="numeric"
,
non è più necessario utilizzare l'hack type="tel"
semanticamente errato.
autocomplete="one-time-code"
L'attributo autocomplete
consente agli sviluppatori di specificare l'autorizzazione che il browser
deve fornire per il completamento automatico e informa il browser sul
tipo di informazioni previste nel campo.
Con autocomplete="one-time-code"
, ogni volta che un utente riceve un messaggio SMS mentre è aperto un modulo, il sistema operativo analizza l'OTP nell'SMS in modo euristico e la tastiera suggerisce l'OTP da inserire. Funziona solo su Safari 12 e versioni successive su iOS, iPadOS e macOS, ma ti consigliamo vivamente di utilizzarlo perché è un modo migliore per migliorare l'esperienza OTP via SMS su queste piattaforme.
autocomplete="one-time-code"
in azione.
autocomplete="one-time-code"
migliora l'esperienza utente, ma puoi fare di più assicurandoti che il messaggio SMS sia conforme al formato del messaggio associato all'origine.
Attributi facoltativi
Gli attributi facoltativi includono:
pattern
specifica il formato a cui deve corrispondere l'OTP inserito. Utilizza le espressioni regolari per specificare il pattern di corrispondenza. Ad esempio,\d{6}
vincola l'OTP a una stringa di sei cifre. Leggi Utilizzare JavaScript per una convalida in tempo reale più complessa per saperne di più supattern
.required
indica che un utente deve compilare il campo.
Per altri consigli, leggi le nostre best practice per i moduli di accesso.
Formattare il testo dell'SMS
Migliora l'esperienza utente di inserimento di una password unica allineandola alla specifica dei codici unici associati all'origine inviati tramite SMS.
La regola di formattazione di base è la seguente: termina il messaggio SMS con il dominio del destinatario preceduto da @
e l'OTP preceduta da #
.
Ad esempio:
Your OTP is 123456
@web-otp.glitch.me #123456
Il formato standard per i messaggi OTP rende l'estrazione più semplice e affidabile. L'associazione dei codici OTP ai siti web rende più difficile indurre gli utenti a fornire un codice a siti dannosi.
Regole di formattazione precise
Le regole precise sono:
- Il messaggio inizia con un testo leggibile (facoltativo) che contiene una stringa alfanumerica di 4-10 caratteri con almeno un numero, lasciando l'ultima riga per l'URL e l'OTP.
- La parte del dominio dell'URL del sito web che ha richiamato l'API deve essere
preceduta da
@
. - L'URL deve contenere
#
, seguito dall'OTP. Il numero di caratteri deve essere pari o inferiore a 140.
L'utilizzo di questo formato offre alcuni vantaggi:
- L'OTP verrà associato al dominio. Se l'utente si trova su domini diversi da quello specificato nel messaggio SMS, il suggerimento OTP non viene visualizzato. In questo modo si riduce anche il rischio di attacchi di phishing e potenziali compromissioni dell'account.
- Il browser ora sarà in grado di estrarre in modo affidabile l'OTP senza dipendere da euristiche misteriose e inaffidabili.
Quando un sito web utilizza autocomplete="one-time-code"
, Safari con iOS 14 o versioni successive
suggerirà l'OTP seguendo queste regole.
Questo formato di messaggio SMS è utile anche per browser diversi da Safari. Chrome, Opera e Vivaldi su Android supportano anche la regola dei codici monouso associati all'origine con l'API WebOTP, anche se non tramite autocomplete="one-time-code"
.
Utilizzare l'API WebOTP
L'API WebOTP fornisce l'accesso all'OTP
ricevuto in un messaggio SMS. Se chiami
navigator.credentials.get()
con il tipo otp
(OTPCredential
), dove transport
include sms
, il sito web
attenderà la ricezione di un SMS conforme ai codici monouso vincolati all'origine
e l'accesso concesso dall'utente. Una volta che l'OTP viene trasmesso a JavaScript,
il sito web può utilizzarlo in un modulo o inviarlo direttamente al server.
navigator.credentials.get({
otp: {transport:['sms']}
})
.then(otp => input.value = otp.code);
Scopri come utilizzare l'API WebOTP in dettaglio in Verificare i numeri di telefono sul web
con l'API WebOTP
o copia e incolla il seguente snippet. Assicurati di impostare un attributo action
e
method
nel tuo <form>
.
// Feature detection
if ('OTPCredential' in window) {
window.addEventListener('DOMContentLoaded', e => {
const input = document.querySelector('input[autocomplete="one-time-code"]');
if (!input) return;
// Cancel the WebOTP API if the form is submitted manually.
const ac = new AbortController();
const form = input.closest('form');
if (form) {
form.addEventListener('submit', e => {
// Cancel the WebOTP API.
ac.abort();
});
}
// Invoke the WebOTP API
navigator.credentials.get({
otp: { transport:['sms'] },
signal: ac.signal
}).then(otp => {
input.value = otp.code;
// Automatically submit the form when an OTP is obtained.
if (form) form.submit();
}).catch(err => {
console.log(err);
});
});
}