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




security passwords (12)

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

https://code.i-harness.com


  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.


Alcune persone credono che sia necessario sovrascrivere la memoria utilizzata per memorizzare la password quando non è più necessaria. Ciò riduce la finestra temporale in cui un utente malintenzionato deve leggere la password dal proprio sistema e ignora completamente il fatto che l'utente malintenzionato ha già bisogno di accesso sufficiente per dirottare la memoria JVM per farlo. Un aggressore con un tale accesso può catturare i tuoi eventi chiave rendendolo completamente inutile (AFAIK, quindi correggimi se sbaglio).

Aggiornare

Grazie ai commenti devo aggiornare la mia risposta. Apparentemente ci sono due casi in cui questo può aggiungere un (molto) minore miglioramento della sicurezza in quanto riduce il tempo che una password potrebbe atterrare sul disco rigido. Comunque penso che sia eccessivo per la maggior parte dei casi d'uso.

  • Il tuo sistema di destinazione potrebbe essere configurato male o devi supporre che sia e devi essere paranoico sui core dump (può essere valido se i sistemi non sono gestiti da un amministratore).
  • Il tuo software deve essere eccessivamente paranoico per prevenire perdite di dati con l'hacker che ha accesso all'hardware - usando cose come TrueCrypt (fuori produzione), VeraCrypt o CipherShed .

Se possibile, disabilitare i core dump e il file di swap si prenderà cura di entrambi i problemi. Tuttavia, richiederebbero i diritti di amministratore e potrebbero ridurre la funzionalità (meno memoria da utilizzare) e la rimozione della RAM da un sistema in esecuzione rappresenterebbe ancora un problema valido.


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.


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.


Non penso che questo sia un suggerimento valido, ma, posso almeno indovinare il motivo.

Penso che la motivazione sia quella di voler essere sicuro di poter cancellare tutte le tracce della password in memoria prontamente e con certezza dopo l'uso. Con un char[] potresti sovrascrivere ogni elemento dell'array con uno spazio vuoto o qualcosa di sicuro. Non è possibile modificare il valore interno di una String questo modo.

Ma quella sola non è una buona risposta; perché non assicurarti solo che un riferimento al char[] o String non sfugga? Quindi non c'è alcun problema di sicurezza. Ma il fatto è che gli oggetti String possono essere intern() ed in teoria e mantenuti in vita all'interno del pool costante. Suppongo che l'uso di char[] impedisca questa possibilità.


Questi sono tutti i motivi, si dovrebbe scegliere char [] array invece di String per password.

1. Poiché 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é String viene utilizzato nel pool di stringhe per riusabilità, è molto probabile che rimanga in memoria a lungo durata, che rappresentano una minaccia per la sicurezza. Dal momento che chiunque abbia accesso al dump della memoria può trovare la password in chiaro e questa è un'altra ragione per cui si dovrebbe sempre usare una password crittografata rispetto al testo normale. Poiché le stringhe non sono modificabili, non è possibile modificare il contenuto delle stringhe perché qualsiasi modifica produrrà una nuova stringa, mentre se si char [] è ancora possibile impostare tutti i suoi elementi come vuoti o nulli. Pertanto, la memorizzazione della password nell'array di caratteri attenua chiaramente il rischio di sicurezza di furto della password.

2. Java stesso consiglia di utilizzare il metodo getPassword () di JPasswordField che restituisce un metodo char [] e getText () che restituisce la password in chiaro, indicando il motivo di sicurezza. È buono seguire i consigli del team di Java e aderire allo standard piuttosto che andare contro di esso.

3. Con String 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. anche se non è una vera ragione, ma ha ancora senso.

    String strPassword="Unknown";
    char[] charPassword= new char[]{'U','n','k','w','o','n'};
    System.out.println("String password: " + strPassword);
    System.out.println("Character password: " + charPassword);

    String password: Unknown
    Character password: [[email protected]

Riferimento da: http://javarevisited.blogspot.com/2012/03/why-character-array-is-better-than.html Spero che questo aiuti.


Le stringhe sono immutabili . Ciò significa che una volta creata la String , se un altro processo può eseguire il dump della memoria, non c'è modo (a parte la reflection ) di liberarsi dei dati prima che la raccolta dati venga presa a calci.

Con un array, puoi cancellare i dati in modo esplicito dopo aver finito. Puoi sovrascrivere l'array con qualsiasi cosa tu voglia e la password non sarà presente in nessun punto del sistema, anche prima della garbage collection.

Quindi sì, questo è un problema di sicurezza - ma anche l'uso di char[] riduce solo la finestra di opportunità per un utente malintenzionato, ed è solo per questo specifico tipo di attacco.

Come notato nei commenti, è possibile che gli array che vengono spostati dal garbage collector lascino in memoria le copie vaganti dei dati. Credo che questo sia specifico per l'implementazione: il garbage collector può cancellare tutta la memoria nel suo svolgimento, per evitare questo genere di cose. Anche se lo fa, c'è ancora il tempo durante il quale il char[] contiene i caratteri reali come una finestra di attacco.


1) Poiché 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é String viene utilizzato nel pool di stringhe per riusabilità, è molto probabile che rimanga in memoria per la lunga durata, che rappresenta una minaccia per la sicurezza. Dal momento che chiunque abbia accesso al dump della memoria può trovare la password in chiaro e questa è un'altra ragione per cui si dovrebbe sempre usare una password crittografata rispetto al testo normale. Poiché le stringhe sono immutabili, non è possibile modificare il contenuto delle stringhe perché qualsiasi modifica produrrà una nuova stringa, mentre se si char [] è ancora possibile impostare tutti i suoi elementi come vuoti o nulli. Pertanto, la memorizzazione della password nell'array di caratteri riduce il rischio di sicurezza di furto della password.

2) Java raccomanda di utilizzare il metodo getPassword () di JPasswordField che restituisce un metodo char [] e getText () che restituisce la password in chiaro, indicando il motivo di sicurezza. È bene seguire i consigli del team di Java e aderire allo standard piuttosto che andare contro di esso.


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 in java è immutabile. Quindi, ogni volta che viene creata una stringa, essa rimarrà nella memoria fino a quando non viene raccolta. Quindi chiunque abbia accesso alla memoria può leggere il valore della stringa.
Se il valore della stringa viene modificato, verrà creata una nuova stringa. Quindi sia il valore originale che il valore modificato rimangono nella memoria fino a quando non viene raccolto.

Con l'array di caratteri, il contenuto dell'array può essere modificato o cancellato una volta che lo scopo della password è servito. Il contenuto originale dell'array non verrà trovato in memoria dopo che è stato modificato e anche prima che la garbage collection abbia effetto.

A causa della sicurezza, è meglio memorizzare la password come array di caratteri.


Le stringhe sono immutabili e non possono essere modificate una volta che sono state create. La creazione di una password come una stringa lascerà riferimenti vaghi alla password nell'heap o nel lotto di stringhe. Ora se qualcuno prende un dump dell'heap del processo Java e analizza attentamente potrebbe essere in grado di indovinare le password. Ovviamente queste stringhe non usate saranno raccolte da garbage ma dipende da quando il GC entra in gioco.

D'altra parte, char [] sono modificabili non appena l'autenticazione è terminata, è possibile sovrascriverli con qualsiasi carattere come tutte le M o le barre inverse. Ora anche se qualcuno prende una discarica dell'heap potrebbe non essere in grado di ottenere le password che non sono attualmente in uso. Questo ti dà un maggiore controllo nel senso, come liberare il contenuto dell'oggetto da te stesso in attesa che il GC lo faccia.





char