Ritorno
Tech 7 min di lettura - 28 apr. 21 - David Rigaux

Come implementare un sistema di doppia autenticazione via SMS?

Un sistema di doppia autenticazione permette di aggiungere un livello di verifica sull'identità di un utente che desidera connettersi a una piattaforma o un'applicazione. Può essere visto come un onere dagli utenti perché richiede un passaggio aggiuntivo per accedere al contenuto desiderato, ma in alcuni casi è essenziale per garantire la sicurezza dei dati degli utenti. La doppia autenticazione rende anche più difficile l'automazione della connessione da parte di un robot, riducendo le possibilità di spam e frodi. Considerata come un metodo di autenticazione forte, la doppia autenticazione obbliga i tuoi utenti a fornire due prove di identità distinte. Questa metodo di autenticazione la si incontra molto spesso, senza nemmeno rendersene conto, con il pagamento tramite carta di credito. Infatti, pagare con la tua carta di credito inserendo il tuo codice segreto è una forma di doppia autenticazione, la prima prova essendo il possesso della carta di credito e la seconda, il codice segreto.
Ci fu un tempo in cui la maggior parte delle autenticazioni a due fattori (A2F) venivano effettuate via email. Autenticarsi via email può essere fastidioso per l'utente: dover aprire la propria casella di posta, aspettare che l'email arrivi, aprirla, quindi copiare e incollare il codice o cliccare su un link può scoraggiarne più di uno. Inoltre, una casella di posta può essere aperta contemporaneamente su una moltitudine di dispositivi diversi, aumentando il numero di vettori di intrusione possibili.
Come avrai sicuramente intuito dal titolo di questo articolo, vedremo come implementare un sistema di A2F utilizzando gli SMS. Il principio è che l'utente conferma la sua autenticazione inserendo un codice che riceve via SMS, chiamato One Time Password (OTP) . Questo mezzo di doppia autenticazione è più user friendly, soprattutto con la possibilità aggiunta dalla versione di iOS 12 di riempire automaticamente un campo con il codice ricevuto via SMS.
bd831548b5e94ad58c1f4691fbfa217b
Nel seguito di questo articolo, vedremo come possiamo implementare una doppia autenticazione via SMS su un'applicazione in React Native.

Flow

Al fine di integrare questo sistema di doppia autenticazione, concentriamoci prima sulla sequenza degli eventi.
Sulla nostra applicazione, quando un utente cercherà di connettersi, genereremo un OTP e lo salveremo in un database indicando una data di scadenza. Utilizzando un'API, invieremo quindi questo codice via SMS all'utente, che potrà poi inserirlo per completare l'autenticazione.
Sequence Diagram
Schema degli scambi tra il frontend, il backend e l'API SMS

Prerequisiti

Nel seguito dell'articolo, supponiamo che esista un sistema di autenticazione con login e password, e spieghiamo come integrarlo con una verifica via SMS. Supponiamo anche che il numero di telefono degli utenti sia registrato nel database.
Vengono utilizzate le seguenti tecnologie:

Servizio di invio SMS

Per inviare gli SMS contenenti i codici di verifica, utilizzeremo il servizio Twilio.
Twilio mette anche a disposizione Verify, che è un'API all-in-one che permette di gestire l'invio di codici di verifica. In questo articolo, affinché il metodo presentato sia applicabile a qualsiasi servizio di invio SMS, utilizzeremo l'API classica di invio SMS di Twilio.
Per impostazione predefinita, un numero di spedizione viene mostrato al destinatario dell'SMS. Se desideri che il mittente sia visualizzato in formato alfanumerico, puoi consultare questo articolo.
Screen Shot 2020-07-24 at 12.13.46 PM
Sulla schermata a destra, il nome del mittente è in formato alfanumerico.

Creazione e invio dell'OTP

Una volta che l'utente ha inserito le sue credenziali e che l'applicazione ha verificato che fossero corrette, generiamo un OTP utilizzando la libreria generate-sms-verification-code :
import * as phoneToken from 'generate-sms-verification-code'

const generateUserVerificationCode = () => {
  return phoneToken(4);
}
Qui, viene generato un codice di 4 cifre.
Registriamo quindi il codice nel database con una data di scadenza:
await this.userRepository.update(user.userId, {
  smsOTP: verificationCode,
  otpExpirationDate: moment().add(5, 'm').toDate(),
});
Qui, il codice scade 5 minuti dopo la sua generazione.
Ora dobbiamo inviare il codice via SMS all'utente tramite Twilio. Per questo, è necessario avere il tuo Twilio Account SID e il tuo Twilio Auth Token, entrambi accessibili dalla tua console Twilio.
import * as twilio from 'twilio';

const accountSid = process.env.TWILIO_ACCOUNT_SID; // Your Account SID from www.twilio.com/console
const authToken = process.env.TWILIO_AUTH_TOKEN; // Your Auth Token from www.twilio.com/console

const client = twilio(accountSid, authToken);

async sendSMSToUser(user: User, body: string) {
  const smsSent = await client.messages.create({
    body, 
    to: user.phoneNumber,
    from: process.env.TWILIO_PHONE_NUMBER,
  });
  
  return !!smsSent.sid;
}
Il codice qui sopra crea un client Twilio utilizzato per chiamare l'API di invio SMS con il metodo create dell'oggetto messages. Puoi trovare il codice completo della generazione e dell'invio del codice integrato in un sistema di autenticazione qui.

Inserimento del codice di verifica

Ora che i tuoi utenti ricevono un codice quando cercano di connettersi, devono poterlo inserire nella tua applicazione per finalizzare l'autenticazione. Per questo utilizziamo la libreria react-native-confirmation-code-field, che permette di creare campi di testo specificamente fatti per i codici.
CleanShot 2021-02-11 at 20.33.45
Esempio di schermata codificata in React Native che permette di inserire un codice
Questa libreria ci lascia la possibilità di chiamare automaticamente una funzione quando il codice di verifica è stato completamente inserito (grazie alla proprietà onFulfill), così come di compilare automaticamente il codice inviato via SMS su iOS.
Nel nostro codice, abbiamo chiamato questa funzione onCodeInputFulfilled : invia il codice inserito dall'utente al backend, che restituisce una risposta al frontend indicando se il codice è valido o meno, con un errore se del caso. A seconda del risultato, l'utente viene reindirizzato a una schermata di successo, oppure gli viene mostrato un messaggio di errore.
const onCodeInputFulfilled = (value: string) => {
  setIsProcessing(true);
  submitVerificationCode(value, route.params.userId).then((res) => {
    setIsProcessing(false);
    if (res.success) {
      navigation.navigate('SuccessScreen');
    } else {
      setErrorMessage(res.errorMessage);
    }
  });
};

Verifica del codice

Ecco il codice backend che permette di verificare se il codice inviato via SMS è valido:
@Post('/verifyCode')
async verifyUserCode(@Body() data, @Res() res) {
  const verificationResult = await this.userService.verifyUserCode(
    data.userId,
    data.verificationCode,
  );

  res.status(HttpStatus.OK).send({
    success: verificationResult.success,
    errorMessage: verificationResult.errorMessage,
  });
}}
Qui, la funzione verifyUserCode viene chiamata in seguito a una richiesta alla route /verifyCode. Chiama un'altra funzione verifyUserCode presente nel servizio NestJS che gestisce gli utenti, che abbiamo chiamato qui userService :
async verifyUserCode(userId: number, verificationCode: string) {
  const retrievedUser = await this.userRepository.findOne({ userId });

  if (verificationCode !== retrievedUser.smsOTP) {
    return { success: false, errorMessage: 'Wrong verification code' };
  } else if (moment().isAfter(retrievedUser.otpExpirationDate)) {
    return { success: false, errorMessage: 'Verification code expired' };
  } else {
    return { success: true };
  }
}
Questa funzione verifica che il codice inserito dall'utente e il codice generato e registrato nel database siano gli stessi. Verifica anche che il codice non sia scaduto.
Il risultato viene quindi inviato al frontend, con un errore se del caso.

Conclusione

Bravo! Hai appena imparato come integrare un sistema di doppia autenticazione che utilizza un codice di verifica inviato via SMS, con compilazione automatica del codice ricevuto su iOS. Abbiamo realizzato questo utilizzando React Native e NestJS, ma la logica presentata può essere applicata ad altre tecnologie.
Riassumiamo quanto abbiamo visto nell'articolo. Per integrare a un'autenticazione semplice un sistema di autenticazione a due fattori via SMS, è necessario prima di tutto assicurarsi di essere in possesso dei numeri di telefono dei tuoi utenti. Nel momento in cui l'utente preme il pulsante di connessione della tua applicazione, una verifica delle credenziali deve essere effettuata sul tuo backend. Se sono corrette, è necessario generare un OTP, salvarlo nel tuo database associandolo all'utente e inviarlo via SMS utilizzando un'API di invio SMS. Dal backend, quando hai la conferma dell'invio dell'SMS, puoi quindi inviare una risposta al frontend per confermare l'invio dell'SMS. Nel momento in cui l'applicazione riceve questa conferma, è necessario cambiare la schermata mostrata all'utente e lasciargli la possibilità di inserire questo OTP appena ricevuto. Quando l'utente ha finito di inserire il codice ricevuto, è necessario inviarlo tramite una richiesta al backend per validarlo. La validazione dell'OTP avviene confrontando quello memorizzato nel database prima dell'invio dell'SMS con quello inserito nell'applicazione (verificando anche la data di scadenza). Se il codice inserito è quello corretto, l'utente è autenticato e può essere reindirizzato alla schermata appropriata.
Per migliorare l'esperienza utente, si consiglia di mostrare un pulsante che permetta di rinviare il codice se non viene ricevuto. È preferibile renderlo inattivo una volta premuto per 15-30 secondi, per evitare numerosi invii che possono essere costosi e sovraccaricare il backend dell'applicazione.
Ecco il codice sorgente del sistema implementato:
Infine, ecco una GIF che illustra il percorso completo del sistema di autenticazione appena implementato:
CleanShot 2021-02-11 at 20.38.34

Referenze

Desideri essere accompagnato per lanciare il tuo progetto digitale ?

Invia il tuo progetto ora