Risposta breve
perché non posso semplicemente dire:
SecureString password = new SecureString("password");
Perché ora hai password
in memoria; senza alcun modo per cancellarlo, che è esattamente il punto di SecureString .
Risposta lunga
Il motivo per cui esiste SecureString è perché non è possibile utilizzare ZeroMemory per cancellare i dati sensibili al termine. Esiste per risolvere un problema esistente a causa del CLR.
In una normale applicazione nativa chiameresti SecureZeroMemory
:
Riempie un blocco di memoria con zeri.
Nota : SecureZeroMemory è identico a ZeroMemory
, tranne per il fatto che il compilatore non lo ottimizzerà.
Il problema è che non puoi chiamare ZeroMemory
o SecureZeroMemory
all'interno di .NET. E in .NET le stringhe sono immutabili; non puoi nemmeno sovrascrivere il contenuto della stringa come puoi fare in altre lingue:
//Wipe out the password
for (int i=0; i<password.Length; i++)
password[i] = \0;
Che cosa si può fare? Come possiamo fornire in .NET la possibilità di cancellare una password o il numero di una carta di credito dalla memoria quando abbiamo finito?
L'unico modo per farlo sarebbe quello di posizionare la stringa in un blocco di memoria nativo , dove è possibile chiamare ZeroMemory
. Un oggetto memoria nativa come:
- un BSTR
- un HGLOBAL
- CoTaskMem memoria non gestita
SecureString restituisce l'abilità persa
In .NET, le stringhe non possono essere cancellate quando hai finito con loro:
- sono immutabili; non puoi sovrascriverne il contenuto
- non puoi
Dispose
da loro
- la loro pulizia è in balia del garbage collector
SecureString esiste come un modo per aggirare la sicurezza delle stringhe ed essere in grado di garantirne la pulizia quando è necessario.
Hai fatto la domanda:
perché non posso semplicemente dire:
SecureString password = new SecureString("password");
Perché ora hai password
in memoria; senza alcun modo per cancellarlo. È bloccato lì fino a quando il CLR non decide di riutilizzare quella memoria. Ci hai riportato proprio dove abbiamo iniziato; un'applicazione in esecuzione con una password di cui non possiamo liberarci e in cui un dump della memoria (o Process Monitor) può vedere la password.
SecureString utilizza l'API Data Protection per archiviare la stringa crittografata in memoria; in questo modo la stringa non esisterà nei file di scambio, nei dump di arresto anomalo o nella finestra delle variabili locali con un collega che osserva il tuo dovere.
Come leggo la password?
Quindi la domanda è: come interagisco con la stringa? È assolutamente non si desidera che un metodo come:
String connectionString = secureConnectionString.ToString()
perché ora sei tornato da dove hai iniziato: una password di cui non puoi liberarti. Volete costringere gli sviluppatori a gestire correttamente la stringa sensibile, in modo che possa essere cancellata dalla memoria.
Ecco perché .NET offre tre utili funzioni di supporto per eseguire il marshalling di un SecureString in una memoria non gestita:
Convertire la stringa in un BLOB di memoria non gestito, gestirla e quindi cancellarla di nuovo.
Alcune API accettano SecureStrings . Ad esempio in ADO.net 4.5 SqlConnection.Credential accetta un set SqlCredential :
SqlCredential cred = new SqlCredential(userid, password); //password is SecureString
SqlConnection conn = new SqlConnection(connectionString);
conn.Credential = cred;
conn.Open();
Puoi anche modificare la password all'interno di una stringa di connessione:
SqlConnection.ChangePassword(connectionString, cred, newPassword);
E ci sono molti posti all'interno di .NET in cui continuano ad accettare una semplice stringa a fini di compatibilità, quindi si trasformano rapidamente e la mettono in un SecureString.
Come inserire il testo in SecureString?
Questo lascia ancora il problema:
Come posso ottenere una password in SecureString in primo luogo?
Questa è la sfida, ma il punto è farti pensare alla sicurezza.
A volte la funzionalità è già fornita per te. Ad esempio, il controllo PasswordP WPF può restituire direttamente la password immessa come SecureString :
Ottiene la password attualmente detenuta da PasswordBox come SecureString .
Questo è utile perché ovunque passavi intorno a una stringa non elaborata, ora hai il sistema di tipo che si lamenta che SecureString è incompatibile con String. Vuoi andare il più a lungo possibile prima di dover riconvertire SecureString in una stringa normale.
La conversione di un SecureString è abbastanza semplice:
- SecureStringToBSTR
- PtrToStringBSTR
come in:
private static string CreateString(SecureString secureString)
{
IntPtr intPtr = IntPtr.Zero;
if (secureString == null || secureString.Length == 0)
{
return string.Empty;
}
string result;
try
{
intPtr = Marshal.SecureStringToBSTR(secureString);
result = Marshal.PtrToStringBSTR(intPtr);
}
finally
{
if (intPtr != IntPtr.Zero)
{
Marshal.ZeroFreeBSTR(intPtr);
}
}
return result;
}
Semplicemente non vogliono che tu lo faccia.
Ma come posso ottenere una stringa in un SecureString? Bene, quello che devi fare è smettere di avere una password in una stringa in primo luogo. È necessario avere in qualcosa d'altro. Anche un Char[]
array sarebbe utile.
Ecco quando puoi aggiungere ogni personaggio e cancellare il testo in chiaro al termine:
for (int i=0; i < PasswordArray.Length; i++)
{
password.AppendChar(PasswordArray[i]);
PasswordArray[i] = (Char)0;
}
È necessario che la password sia memorizzata in un po 'di memoria da poter cancellare. Caricalo nel SecureString da lì.
tl; dr: esiste SecureString per fornire l'equivalente di ZeroMemory .
Alcune persone non vedono il punto nel cancellare la password dell'utente dalla memoria quando un dispositivo è bloccato o nel cancellare i tasti premuti dalla memoria dopo che sono stati autenticati . Quelle persone non usano SecureString.
SecureString
per il nuovo sviluppo: github.com/dotnet/platform-compat/blob/master/docs/DE0001.md