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



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
Question

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[] .




  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.




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.




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.




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? Può 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:




String in java is immutable. So whenever a string is created, it will remain in the memory until it is garbage collected. So anyone who has access to the memory can read the value of the string.
If the value of the string is modified then it will end up creating a new string. So both the original value and the modified value stay in the memory until it is garbage collected.

With the character array, the contents of the array can be modified or erased once the purpose of the password is served. The original contents of the array will not be found in memory after it is modified and even before the garbage collection kicks in.

Because of the security concern it is better to store password as a character array.




The short and straightforward answer would be because char[] is mutable while String objects are not.

Strings in Java are immutable objects. That is why they can't be modified once created, and therefore the only way for their contents to be removed from memory is to have them garbage collected. It will be only then when the memory freed by the object can be overwritten, and the data will be gone.

Now garbage collection in Java doesn't happen at any guaranteed interval. The String can thus persist in memory for a long time, and if a process crashes during this time, the contents of the string may end up in a memory dump or some log.

With a character array , you can read the password, finish working with it as soon as you can, and then immediately change the contents.




Related