java - Perché char [] è preferito a String per le password?




8 Answers

Mentre altri suggerimenti qui sembrano validi, c'è un altro buon motivo. Con la String semplice hai molte più possibilità di stampare accidentalmente la password su registri , monitor o qualche altro posto non sicuro. char[] è meno vulnerabile.

Considera questo:

public static void main(String[] args) {
    Object pw = "Password";
    System.out.println("String: " + pw);

    pw = "Password".toCharArray();
    System.out.println("Array: " + pw);
}

stampe:

String: Password
Array: [C@5829428e
java string security passwords char

In Swing, il campo password ha un getPassword() (restituisce char[] ) invece del solito getText() (restituisce String ). Allo stesso modo, ho trovato un suggerimento di non usare String per gestire le password.

Perché String pone una minaccia alla sicurezza quando si tratta di password? È scomodo usare char[] .




Gli array di char[] ( char[] ) possono essere cancellati dopo l'uso impostando ogni carattere su zero e Stringhe no. Se qualcuno può in qualche modo vedere l'immagine di memoria, può vedere una password in testo normale se vengono utilizzate le stringhe, ma se viene utilizzato char[] , dopo aver eliminato i dati con 0, la password è sicura.




  1. Le stringhe sono immutabili in Java se si memorizza la password come testo normale sarà disponibile in memoria fino a quando Garbage Collector non lo cancella e poiché le stringhe vengono utilizzate nel pool di stringhe per la riutilizzabilità ci sono possibilità piuttosto elevate che rimanga in memoria per un lungo durata, che rappresenta una minaccia per la sicurezza. Dal momento che chiunque abbia accesso al dump della memoria può trovare la password in chiaro
  2. Raccomandazione Java che utilizza il metodo getPassword() di JPasswordField che restituisce un metodo char [] e deprecato getText() che restituisce la password in chiaro, indicando il motivo di sicurezza.
  3. toString () c'è sempre il rischio di stampare testo normale in file di log o console, ma se si usa Array non si stamperà il contenuto dell'array, ma si stamperà la sua posizione di memoria.

    String strPwd = "passwd";
    char[] charPwd = new char[]{'p','a','s','s','w','d'};
    System.out.println("String password: " + strPwd );
    System.out.println("Character password: " + charPwd );
    

    Parola d'ordine stringa: passwd

    Password caratteri: [C @ 110b2345

Considerazioni finali: sebbene l'uso di char [] non sia sufficiente, è necessario cancellare il contenuto per renderlo più sicuro. Suggerisco anche di lavorare con hash o password cifrata invece di testo normale e di cancellarlo dalla memoria non appena l'autenticazione è completata.




La risposta è già stata data, ma mi piacerebbe condividere un problema che ho scoperto ultimamente con le librerie standard Java. Mentre si preoccupano ora di sostituire le stringhe di password con char[] ovunque (che ovviamente è una buona cosa), altri dati critici per la sicurezza sembrano essere trascurati quando si tratta di cancellarlo dalla memoria.

Sto pensando ad esempio alla classe PrivateKey . Considera uno scenario in cui devi caricare una chiave RSA privata da un file PKCS # 12, utilizzandola per eseguire alcune operazioni. Ora, in questo caso, il solo sniffing della password non sarebbe di grande aiuto fin tanto che l'accesso fisico al file chiave fosse opportunamente limitato. Come attaccante, sarebbe molto meglio se ottenessi direttamente la chiave invece della password. Le informazioni desiderate possono essere trapelate molteplici, core dump, una sessione di debugger o file di swap sono solo alcuni esempi.

E a quanto pare, non c'è nulla che ti permetta di cancellare le informazioni private di un PrivateKey dalla memoria, perché non c'è alcuna API che ti permetta di cancellare i byte che formano le informazioni corrispondenti.

Questa è una brutta situazione, in quanto questo paper descrive come questa circostanza potrebbe essere potenzialmente sfruttata.

La libreria OpenSSL, ad esempio, sovrascrive le sezioni di memoria critica prima che le chiavi private vengano liberate. Poiché Java è stato sottoposto a raccolta dei dati inutili, occorrerebbero metodi espliciti per cancellare e invalidare le informazioni private per le chiavi Java, che devono essere applicate immediatamente dopo l'uso della chiave.




Modifica: Tornando a questa risposta dopo un anno di ricerche sulla sicurezza, mi rendo conto che ciò comporta l'implicazione piuttosto sfortunata di poter effettivamente confrontare le password in chiaro. Per favore non farlo. Utilizzare un hash unidirezionale sicuro con un sale e un numero ragionevole di iterazioni . Prendi in considerazione l'utilizzo di una libreria: questa roba è difficile da ottenere!

Risposta originale: per quanto riguarda il fatto che String.equals () utilizza la valutazione di cortocircuito ed è quindi vulnerabile a un attacco di temporizzazione? Potrebbe essere improbabile, ma in teoria è possibile calcolare il confronto delle password per determinare la sequenza corretta dei caratteri.

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        // Quits here if Strings are different lengths.
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            // Quits here at first different character.
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

Altre risorse su attacchi di temporizzazione:




Non c'è nulla che l'array di char ti dia rispetto a String a meno che non lo pulisci manualmente dopo l'uso, e non ho visto nessuno farlo davvero. Quindi per me la preferenza di char [] vs String è un po 'esagerata.

Dai un'occhiata alla vasta libreria Spring Security here usata e chiediti: le password incompetenti o char [] di Spring Security non hanno molto senso. Quando un brutto hacker afferra i dump di memoria della tua RAM assicurati che otterrà tutte le password anche se usi metodi sofisticati per nasconderle.

Tuttavia, Java cambia continuamente e alcune funzionalità spaventose come la funzionalità di deduplicazione delle stringhe di Java 8 potrebbero internare gli oggetti String a tua insaputa. Ma questa è una conversazione diversa.




La risposta breve e diretta sarebbe perché char[]è mutabile mentre gli Stringoggetti non lo sono.

Stringsin Java sono oggetti immutabili. Questo è il motivo per cui non possono essere modificati una volta creati, e quindi l'unico modo per rimuovere i loro contenuti dalla memoria è quello di averli raccolti. Sarà solo allora quando la memoria liberata dall'oggetto può essere sovrascritta, e i dati saranno spariti.

Ora la garbage collection in Java non si verifica in nessun intervallo garantito. Il Stringpuò quindi persistere in memoria per un lungo periodo di tempo, e se un processo si blocca durante questo periodo, il contenuto della stringa potrebbe finire in un dump della memoria o in qualche registro.

Con un array di caratteri , puoi leggere la password, terminare di lavorare il prima possibile, e quindi modificare immediatamente il contenuto.




La stringa è immutabile e va al pool di stringhe. Una volta scritto, non può essere sovrascritto.

char[] è un array che dovresti sovrascrivere una volta che hai usato la password e questo è come dovrebbe essere fatto:

char[] passw = request.getPassword().toCharArray()
if (comparePasswords(dbPassword, passw) {
 allowUser = true;
 cleanPassword(passw);
 cleanPassword(dbPassword);
 passw=null;
}

private static void cleanPassword (char[] pass) {
 for (char ch: pass) {
  ch = null;
 }
}

Uno scenario in cui l'hacker potrebbe utilizzarlo è un crashdump: quando la JVM si arresta in modo anomalo e genera un dump della memoria, sarà possibile vedere la password.

Questo non è necessariamente un aggressore esterno malintenzionato. Questo potrebbe essere un utente di supporto che ha accesso al server per scopi di monitoraggio. Poteva sbirciare in un crashdump e trovare le password.




Related