Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Alternative sicure al campo input per le password

Creare alternative sicure al classico campo di input con le password mascherate
Creare alternative sicure al classico campo di input con le password mascherate
Link copiato negli appunti

Questa è la traduzione dell'articolo The Problem with Passwords di Lyle Mullican, pubblicato originariamente su A List Apart il 9 Febbraio 2010. La traduzione viene qui presentata con il consenso dell'editore (A List Apart Magazine) e dell'autore.

Un recente articolo dell'esperto di usabilità Jakob Nielsen propone un cambiamento fondamentale nel campo della progettazione dei campi per le password sul web. Egli ritiene che sia giunto il momento “di mostrare la maggior parte delle password a chiare lettere così come gli utenti le digitano”, abbandonando il metodo tradizionale che visualizza una serie di asterischi o pallini al posto dell'effettiva password.

La proposta controversa di Nielsen dimostra il principio che la maggior parte delle decisioni riguardanti un progetto necessitano di uno scambio di concessioni. Gli obiettivi degli utenti e gli obiettivi di business non sempre si intersecano. Le preoccupazioni circa sicurezza, usabilità ed estetica spesso si pongono in contrasto. Dobbiamo fissare delle priorità ed equilibrare tali interessi al fine di ottenere degli ottimi risultati in ogni situazione.

È difficile occuparsi di questioni di sicurezza, poiché sono una scocciatura. Vogliamo far conoscere alla gente il grande servizio che abbiamo creato, ma invece costruiamo delle barriere tra utente e applicazione. Gli utenti devono dimostrare la loro identità. Non possiamo fidarci di tutti i dati che vengono immessi a meno che non siano stati completamente depurati.

Sfortunatamente, questa è la realtà. Una grande quantità di traffico web è pericoloso e il furto di dati sensibili è cosa comune. In genere, per accedere ad un'applicazione agli utenti viene chiesto di fornire un nome utente (spesso un indirizzo e-mail), insieme ad una password. Il nome utente identifica la persona, mentre la password dimostra che la persona che inserisce il nome utente è effettivamente quella che ha creato l'account. Questa è la teoria, basata su due assunti:

  • Una password non potrà mai essere visibile al di fuori della mente di chi l'ha creata.
  • Sia il nome utente che la password possono essere richiamati dalla memoria quando è necessario.

Questo approccio pone un significativo onere cognitivo sulle persone che adoperano siti web che richiedono l'autenticazione. Generalmente, otteniamo molto, ma facilmente si notano i punti deboli del sistema. Le password facili da ricordare sono anche facili da indovinare. Quando le persone sono costrette a scegliere delle password sicure, devono scriverle altrimenti le dimenticano. La risposta abituale è un meccanismo di reimpostazione della password, che naturalmente mina la forza dell'intero sistema. Non importa se la mia password sia crittografata con le cifre più impensabili che l'uomo conosca quando può essere semplicemente azzerata da chi sa quale liceo ho frequentato.

Questo è uno dei motivi per cui Nielsen suggerisce l'abbandono del mascheramento della password. La gente si innervosisce e spesso resetta le password che in realtà non ha dimenticato solo perché l'ha digitata male. Fornendo un feedback chiaro e a chiare lettere si ridurranno gli errori, migliorerà l'esperienza degli utenti e si ridurranno le necessità di implementare alternative meno sicure.

Tuttavia, fare un cambiamento così radicale a un'interazione con l'utente tanto fondamentale potrebbe presentare gravi problemi. Prendiamo in considerazione alcuni contesti in cui si potrebbe aver bisogno di una password da inserire davanti a un folto gruppo di persone, ad esempio mentre si utilizza un proiettore per la sala conferenze. E molti anni di esperienza sul web da parte degli utenti hanno stabilito delle aspettative ben precise su come gli elementi di un form dovrebbero funzionare. La gente ha compreso che il mascheramento della password è stato ideato per la loro sicurezza. Non riuscendo a soddisfare tale aspettativa la fiducia potrebbe essere minata, e non possiamo permetterci di perdere la fiducia dei nostri utenti.

C'è una via di mezzo che possa fornire un feedback e ridurre gli errori nell'uso delle password in modo tale da non sacrificare l'esperienza dell'utente? Almeno due modelli di progettazione affrontano la questione in applicazioni offline, e con un po' di JavaScript possiamo trasferirli sul web.

Ora lo vedi, ora no!

La soluzione più semplice è quella di mascherare la password di default, mentre agli utenti viene dato un sistema per commutare il campo password in uno di testo, a chiare lettere. Nielsen menziona anche questo di passaggio. Questo approccio permette agli utenti di avere la conferma che la password digitata è stata inserita correttamente, ma consegna il controllo nelle mani dell'utente stesso. Tali controlli di attivazione/disattivazione vengono spesso visualizzati sui pannelli di preferenza per il WiFi, ma raramente vengono applicati altrove. (Nota: Mentre questo articolo era in produzione, almeno un blog si dichiarava a favore di una simile tecnica).

Dovrebbe essere semplice creare un controllo che commuta l'attributo type di un elemento input HTML tra text e password. Sfortunatamente, non è così. Internet Explorer non consente che questo particolare attributo venga fissato da JavaScript, quindi bisogna essere un po' più creativi. Il trucco sta nelle seguenti due funzioni:

window.onload = function() {
  if(document.getElementsByTagName) {
    var inputs = document.getElementsByTagName('input');
    for(var i in inputs) {
      var input = inputs[i];
      if(input.type == 'password') {
        toggle_control = document.createElement('label');
        toggle_control.innerHTML = "<input type="checkbox »
        " "+ "onclick="toggle_password('"+ input.id+"',this »
        .checked) " />"+" Show password";
        input.parentNode.insertBefore(toggle_control, input »
        .nextSibling);
      }
    }
  }
}
function toggle_password(element_id, show_text) {
  if(document.getElementById) {
    var password_input = document.getElementById(element_id);
    var new_input      = document.createElement('input');
    with(new_input) {
      id        = password_input.id;
      name      = password_input.name;
      value     = password_input.value;
      size      = password_input.size;
      className = password_input.className;
      type      = show_text ? 'text' : 'password';
    }
    password_input.parentNode.replaceChild(new_input, »
    password_input);
  }
}

La prima funzione esegue la scansione del documento in cerca di tutti gli elementi di input e raccoglie quelli di tipo password. Si noti che questo codice è destinato solo per illustrare il concetto, il processo potrebbe essere migliorato utilizzando un framework JavaScript come Prototype.

Dopo ogni input, la funzione consente di inserire un checkbox con una label per attivare/disattivare il campo tra testo crittografato e non. La seconda funzione controlla il comportamento stesso di attivazione/disattivazione. Quando l'utente clicca sul controllo di attivazione/disattivazione, la funzione crea un nuovo input e lo scambia con quello esistente, manipolando tra di loro il valore e le altre proprietà.

Un approccio alternativo consiste nel creare l'input di testo una sola volta e attivare/disattivare la proprietà di visualizzazione display per mostrare o nascondere il campo appropriato. Uno svantaggio di questo metodo, però, è che l'id di un elemento deve essere univoco. Dal momento che l'input di testo parallelo avrebbe il proprio id, esso non eredita tutte le regole del CSS a cui fa riferimento l'elemento originale con il suo ID.

Date un'occhiata all'esempio in azione. Questa soluzione è facile da realizzare e segue il principio del progressive enhancement. In assenza di JavaScript, i campi per la password manterranno il loro comportamento abituale. Il controllo di attivazione/disattivazione consente all'utente di scegliere se visualizzare o meno una password in una particolare circostanza. Lo svantaggio principale di questo metodo è che esso potrebbe compromettere il concetto che un utente ha del campo password come una "scatola nera". Siamo così completamente abituati a pensare alle nostre password come a un segreto che solo l'idea di visualizzarle a chiare lettere potrebbe essere inquietante.

Fine prima parte.

Una seconda alternativa

Gli errori di digitazione sono particolarmente comuni sui dispositivi a schermo tattile come l'iPhone, dove le dita non riescono a sentire al tatto i bordi dei tasti. Anticipando che gli input delle password senza un feedback visivo potrebbero causare dei problemi, Apple ha adottato un metodo interessante. L'ultima lettera digitata nel campo rimane visibile per pochi secondi prima di trasformarsi in un puntino. Questo crea l'opportunità di rilevare gli errori senza mostrare la password interamente.

Possiamo riprodurre questo comportamento di mascheramento progressivo con HTML e Javascript, sebbene ci vorrà un po' più di codice rispetto all'esempio precedente. Consideriamo quanto segue:

window.onload = function() {
  if(document.getElementsByTagName) {
    var inputs = document.getElementsByTagName('input');
    var password_inputs = Array();
    for(var i in inputs) {
      if(inputs[i].type == 'password') {
        password_inputs.push(inputs[i]);
      }
    }
    for(var i in password_inputs) {
      var input = inputs[i];
      var masking_element = document.createElement('input');
      with(masking_element) {
        style.position = 'absolute';
        id             = input.name + '_mask';
        type           = 'text';
        size           = input.size;
        className      = input.className;
      }
      masking_element.onfocus = function(){this.nextSibling »
      .focus()};
      input.parentNode.insertBefore(masking_element, input);
      input.onchange = function() {
        if(this.timer){
          clearTimeout(this.timer);
        }
        var mask_character = "u2022";
        var last_character = this.value.charAt(this »
        .value.length-1);
        var masked_text    = this.previousSibling.value;
        var password_text  = this.value;
        if(masked_text.length < password_text.length) {
          this.previousSibling.value = password_text.substr(0,
            password_text.length-1).replace(/./g,
            mask_character)+last_character;
        } else {
          this.previousSibling.value = password_text »
          .replace(/./g,mask_character);
        }
        this.timer = setTimeout("with(document.getElement »
        ById('"+masking_element.id+"')){value=value »
        .replace(/./g,'"+mask_character+"')}",2000);
      }
      input.onkeyup = input.onchange;
      input.onchange();
    }
  }
}

Questa volta, creiamo un secondo input di testo per collocarlo direttamente in cima ad ogni input di password (per i CSS si applica l'esempio precedente riguardo all'ereditarietà delle proprietà). Modificando il suo valore quando cambia il campo originale, possiamo controllare ciò che vede l' utente. Osserviamo i singoli step dello script:

window.onload = function() {
  if(document.getElementsByTagName) {
    var inputs = document.getElementsByTagName('input');
    var password_inputs = Array();
    for(var i in inputs) {
      if(inputs[i].type == 'password') {
        password_inputs.push(inputs[i]);
      }
    }
    for(var i in password_inputs) {
      var input = inputs[i];
      ...
    }
  }
}

Ancora una volta, la nostra attività primaria analizza la pagina alla ricerca degli input per le password in modo da poter modificare il loro comportamento. Tuttavia, c'è una differenza fondamentale tra questa funzione e il primo esempio. In Internet Explorer document.getElementsByTagName () al momento in cui lo script viene eseguito, non restituisce una semplice lista di elementi corrispondenti. Piuttosto, restituisce un riferimento all'insieme alla collezione degli elementi corrispondenti. Se creiamo un nuovo elemento input mentre viene eseguito un loop sui risultati, aumenteremo la dimensione di tale insieme a ogni passaggio e il loop continuerà a tempo indeterminato. Questo blocca istantaneamente Internet Explorer (e non con garbo).

Invece, dobbiamo copiare i risultati iniziali della funzione in un array ed eseguire il loop su di esso.

var masking_element = document.createElement('input');
with(masking_element) {
  style.position = 'absolute';
  id             = input.name + '_mask';
  type           = 'text';
  size           = input.size;
  className      = input.className;
}
masking_element.onfocus = function(){this.nextSibling.focus()};
input.parentNode.insertBefore(masking_element, input);

Con il nuovo input inserito direttamente prima di quello esistente, impostando la sua posizione su absolute, esso verrebbe posto direttamente sulla parte superiore. Ciò dovrebbe funzionare nella maggior parte dei layout, ma per posizionarlo correttamente ci possono essere eccezioni in cui è richiesto in aggiunta il CSS. Naturalmente, ora che stiamo coprendo l'input con un altro elemento, dobbiamo anche essere sicuri che cliccando sulla maschera si attivi l'input. L'aggiunta di un gestore onfocus si occuperà di ciò. Dobbiamo assegnare tale gestore al di fuori di with in modo che funzioni correttamente in Firefox 2.

input.onchange = function() {
  ...
}
input.onkeyup = input.onchange;

Con il nuovo elemento posizionato, potremo realizzare una funzione che visualizzi progressivamente il testo mascherato della password . Avremo bisogno che questo testo risponda alle modifiche nel contenuto del campo password. Di solito ciò significa che un utente sta digitando sulla tastiera, ma potrebbe non essere sempre così. Ad esempio, qualcuno potrebbe incollare il testo nel campo utilizzando un menu di scelta rapida. Associando il nostro codice agli eventi change e keyup, essi dovrebbero coprire tutti i casi.

var mask_character = "u2022";
var last_character = this.value.charAt(this.value.length-1);

Per mascherare le password possiamo definire qualsiasi carattere. Tradizionalmente, la maggior parte dei sistemi adoperano l'asterisco o i puntini, così in questo esempio definiamo l'entità Unicode 2022, che è il carattere punto elenco. Nella seconda riga, identifichiamo l'ultimo carattere del valore dell'attuale password in modo che possiamo trasformarlo in testo non crittografato.

var masked_text    = this.previousSibling.value;
var password_text  = this.value;
if(masked_text.length < password_text.length) {
  this.previousSibling.value = password_text.substr(0,
  password_text.length-1).replace(/./g, »
  mask_character)+last_character;
} else {
  this.previousSibling.value = password_text.replace(/./g,
                                 mask_character);
}

Ora possiamo prendere il valore del campo password, sostituire ogni carattere eccetto l'ultimo con il carattere punto elenco e inserire tale testo nel campo che stiamo usando come maschera. Tuttavia, dobbiamo fare ciò solo mentre la persona sta digitando. In altre parole, se l'utente preme il tasto backspace, non vogliamo rivelare nuovamente il carattere precedente. Dopo che è stato nascosto, dovrebbe rimanere nascosto. Così, prima di eseguire la sostituzione, per prima cosa controlliamo per vedere se il valore della password è più lungo rispetto al testo mascherato. La sostituzione stessa può essere fatta utilizzando una semplice espressione regolare.

L'espressione /./ nel campo password corrisponde a qualsiasi carattere. Aggiungendo la lettera g, alla fine, (/./ g) significa che esso analizza l'intera stringa di testo invece di fermarsi alla prima corrispondenza.

this.timer = setTimeout("with(document.getElementById('"+
  masking_element.id+"')){value=value.replace(/./g,'"+
  mask_character+"')}",2000);

Dopo un ritardo di due secondi, possiamo mascherare l'intera password. Tuttavia, i nostri utenti dopo aver digitato ogni lettera probabilmente non faranno una pausa di due secondi. Così, vogliamo soltanto che il comportamento abbia luogo quando il campo password non sia stato modificato per un tale periodo di tempo. Ogni volta che richiamiamo in Javascript la funzione setTimeout, esso restituisce un ID che possiamo utilizzare per fare riferimento a quel particolare intervallo.

if(this.timer){
  clearTimeout(this.timer);
}

Memorizzando l'ID del timer in una variabile e aggiungendo il codice sopra riportato all'inizio della nostra funzione, possiamo cancellare il conto alla rovescia fintanto che osserviamo che il campo è ancora in fase di modifica.

input.onchange();

L'ultimo passo è quello di eseguire la funzione che abbiamo appena definito. Questo assicura che se il campo password è stato pre-compilato prima che la pagina sia stata caricata, la maschera mostrerà il testo correttamente.
Per vedere l'intero script in azione, date un'occhiata all'esempio due. Esso è stato testato in Internet Explorer 6-8, Firefox, Safari e Chrome. Ancora una volta, in assenza di JavaScript, questa tecnica degraderà perfettamente — semplicemente i campi password funzioneranno normalmente.

Procedete con cautela

Quando si tratta di un'area così fondamentale dell'esperienza utente sul web, dobbiamo stare attenti, perché abbiamo a che fare con delle aspettative fortemente condizionate. Il metodo di protezione delle applicazioni web nome utente/password è diventato il metodo standard anche se non è perfetto, tuttavia ci sono poche buone alternative. Possiamo affrontare i problemi di usabilità dei campi password testando le modifiche come queste senza compromettere la consapevolezza fondamentale e perdere la fiducia dei nostri utenti.

Traduzione a cura di Cinzia Pasqualino.

Ti consigliamo anche