Domanda

Sto cercando di capire lo scopo di SecureString di .NET. Da MSDN:

  

Un'istanza della classe System.String è sia immutabile che, quando non è più necessaria, non può essere programmata programmaticamente per la garbage collection; vale a dire, l'istanza è di sola lettura dopo che è stata creata e non è possibile prevedere quando l'istanza verrà eliminata dalla memoria del computer. Di conseguenza, se un oggetto String contiene informazioni riservate come una password, un numero di carta di credito o dati personali, esiste il rischio che le informazioni possano essere rivelate dopo essere state utilizzate poiché l'applicazione non può eliminare i dati dalla memoria del computer.

     

Un oggetto SecureString è simile a un oggetto String in quanto ha un valore di testo. Tuttavia, il valore di un oggetto SecureString viene automaticamente crittografato, può essere modificato fino a quando l'applicazione lo contrassegna come di sola lettura e può essere eliminato dalla memoria del computer dall'applicazione o dal Garbage Collector di .NET Framework.

     

Il valore di un'istanza di SecureString viene automaticamente crittografato quando l'istanza viene inizializzata o quando il valore viene modificato. L'applicazione può rendere l'istanza immutabile e impedire ulteriori modifiche invocando il metodo MakeReadOnly.

La crittografia automatica è il grande vantaggio?

E perché non posso semplicemente dire:

SecureString password = new SecureString("password");

anziché

SecureString pass = new SecureString();
foreach (char c in "password".ToCharArray())
    pass.AppendChar(c);

Quale aspetto di SecureString mi manca?

È stato utile?

Soluzione

Alcune parti del framework che attualmente utilizzano SecureString :

Lo scopo principale è ridurre la superficie di attacco, piuttosto che eliminarla. SecureStrings sono " ; riposte " nella RAM in modo che Garbage Collector non lo sposti o ne faccia copie. Assicura inoltre che il testo in chiaro non venga scritto nel file Swap o nei dump principali. La crittografia è più simile all'offuscamento e non fermerà un determinato hacker, che sarebbe in grado di trovare chiave simmetrica utilizzata per crittografarla e decrittografarla.

Come altri hanno già detto, il motivo è necessario creare un SecureString carattere per carattere è dovuto al primo ovvio difetto di fare diversamente: presumibilmente hai già il valore segreto come semplice stringa, quindi qual è il punto?

SecureString s sono il primo passo per risolvere un problema Chicken-and-Egg, quindi anche se la maggior parte degli scenari attuali richiede di convertirli in stringhe regolari per farne un uso, la loro esistenza nel framework ora significa un migliore supporto per loro in il futuro - almeno fino al punto in cui il tuo programma non deve essere l'anello debole.

Altri suggerimenti

Molte grandi risposte; ecco una breve sintesi di ciò che è stato discusso.

Microsoft ha implementato la classe SecureString nel tentativo di fornire una migliore sicurezza con informazioni sensibili (come carte di credito, password, ecc.). Fornisce automaticamente:

  • crittografia (in caso di dump della memoria o memorizzazione nella pagina)
  • pinning in memory
  • possibilità di contrassegnare come di sola lettura (per impedire ulteriori modifiche)
  • costruzione sicura NON consentendo il passaggio di una stringa costante

Attualmente SecureString è in uso limitato ma prevede una migliore adozione in futuro.

Sulla base di queste informazioni, il costruttore di SecureString non dovrebbe semplicemente prendere una stringa e suddividerla in array di caratteri poiché la stringa spiegata vanifica lo scopo di SecureString.

Informazioni aggiuntive:

  • Un post da .NET Security blog parlando più o meno come coperto qui.
  • E un altro uno rivisitandolo e menzionando uno strumento che PU d scaricare il contenuto di SecureString.

Modifica: ho trovato difficile scegliere la risposta migliore in quanto ci sono buone informazioni in molti; peccato che non ci siano opzioni di risposta assistita.

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 che esiste perché del CLR.

In un'applicazione nativa normale chiameresti SecureZeroMemory :

  

Riempie un blocco di memoria con zeri.

Nota : SecureZeroMemory è identico a ZeroMemory , tranne che il compilatore non lo ottimizzerà via.

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;

Quindi cosa puoi 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 puoi quindi chiamare ZeroMemory . Un oggetto memoria nativa come:

  • un BSTR
  • un HGLOBAL
  • Memoria non gestita di CoTaskMem

SecureString restituisce l'abilità persa

In .NET, le stringhe non possono essere cancellate quando hai finito con esse:

  • sono immutabili; non puoi sovrascriverne il contenuto
  • non puoi Smaltire di 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 posto la domanda:

  

perché non posso semplicemente dire:

String connectionString = secureConnectionString.ToString()

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 posso leggere la password?

Quindi c'è la domanda: come interagisco con la stringa? Non vuoi assolutamente un metodo come:

SqlCredential cred = new SqlCredential(userid, password); //password is SecureString
SqlConnection conn = new SqlConnection(connectionString);
conn.Credential = cred;
conn.Open();

perché ora sei tornato da dove hai iniziato: una password di cui non puoi liberarti. Desideri forzare gli sviluppatori a gestire correttamente la stringa sensibile, in modo che possa essere cancellato dalla memoria.

Ecco perché .NET offre tre utili funzioni di supporto per eseguire il marshalling di un SecureString in una memoria non gestita:

Converti la stringa in un BLOB di memoria non gestito, la gestisci e quindi la cancelli di nuovo.

Alcune API accettano SecureStrings . Ad esempio in ADO.net 4.5 SqlConnection.Credential accetta un set SqlCredential :

SqlConnection.ChangePassword(connectionString, cred, newPassword);

Puoi anche cambiare la password all'interno di una stringa di connessione:

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;
}

E ci sono molti posti all'interno di .NET in cui continuano ad accettare una semplice stringa per motivi di compatibilità, quindi girano rapidamente e inseriscono 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 WPF PasswordBox può restituirti direttamente la password immessa come SecureString :

  

PasswordBox Proprietà .SecurePassword

     

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:

for (int i=0; i < PasswordArray.Length; i++)
{
   password.AppendChar(PasswordArray[i]);
   PasswordArray[i] = (Char)0;
}

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. Dovevi averlo in qualcosa altro. Anche un array Char [] sarebbe utile.

Ecco quando puoi aggiungere ogni carattere e cancellare il testo in chiaro al termine:

<*>

È necessario che la password sia memorizzata nella memoria che è possibile cancellare. Caricalo nel SecureString da lì.


tl; dr: SecureString esiste per fornire l'equivalente di ZeroMemory .

Alcune persone non vedono il punto in cancellando la password dell'utente dalla memoria quando un dispositivo è bloccato o sta cancellando cancellando i tasti premuti dalla memoria dopo che sono stati autenticati . Quelle persone non usano SecureString.

Esistono pochissimi scenari in cui è possibile utilizzare in modo ragionevole SecureString nella versione corrente del Framework. È davvero utile solo per interagire con le API non gestite: puoi eseguirne il marshalling utilizzando Marshal.SecureStringToGlobalAllocUnicode.

Non appena lo converti in / da un System.String, hai annullato il suo scopo.

MSDN sample genera il carattere SecureString alla volta da console input e passa la stringa sicura a un'API non gestita. È piuttosto contorto e irrealistico.

Potresti aspettarti che le versioni future di .NET abbiano un supporto maggiore per SecureString che lo renderà più utile, ad es .:

  • SecureString Console.ReadLineSecure () o simile per leggere l'input della console in un SecureString senza tutto il codice contorto nell'esempio.

  • Sostituzione TextBox WinForms che memorizza la sua proprietà TextBox.Text come stringa sicura in modo che le password possano essere inserite in modo sicuro.

  • Estensioni alle API relative alla sicurezza per consentire il passaggio delle password come SecureString.

Senza quanto sopra, SecureString avrà un valore limitato.

Credo che il motivo per cui devi fare l'aggiunta di caratteri anziché un'istanza piatta sia perché sullo sfondo passa " password " al costruttore di SecureString inserisce quella "password" stringa in memoria che sconfigge lo scopo della stringa sicura.

Aggiungendo alla memoria stai solo mettendo un personaggio alla volta che è come non essere adiacenti l'uno all'altro fisicamente, rendendo molto più difficile ricostruire la stringa originale. Potrei sbagliarmi qui, ma è così che mi è stato spiegato.

Lo scopo della classe è impedire che i dati sicuri vengano esposti tramite un dump della memoria o uno strumento simile.

MS ha scoperto che in alcuni casi di arresto anomalo del server (desktop o altro) c'erano volte in cui l'ambiente di runtime eseguiva un dump della memoria esponendo il contenuto della memoria. Secure String lo crittografa in memoria per impedire all'autore dell'attacco di recuperare il contenuto della stringa.

Uno dei maggiori vantaggi di un SecureString è che si suppone che si eviti la possibilità che i dati vengano archiviati su disco a causa della memorizzazione nella cache della pagina. Se si dispone di una password in memoria e quindi si carica un programma o un set di dati di grandi dimensioni, è possibile che la password venga scritta nel file di scambio man mano che il programma viene esaurito nella memoria. Con un SecureString, almeno i dati non rimarranno indefinitamente sul tuo disco in chiaro.

Immagino sia perché la stringa è pensata per essere sicura, cioè un hacker non dovrebbe essere in grado di leggerla. Se lo inizializzi con una stringa, l'hacker potrebbe leggere la stringa originale.

Bene, come afferma la descrizione, il valore viene archiviato crittografato, con un dump di memoria del processo che non rivelerà il valore della stringa (senza un lavoro abbastanza serio).

Il motivo per cui non puoi semplicemente costruire un SecureString da una stringa costante è perché allora avresti avere in memoria una versione non crittografata della stringa. Limitare la creazione della stringa in pezzi riduce il rischio di avere l'intera stringa in memoria contemporaneamente.

Smetterei di usare SecureString. Sembra che i ragazzi PG stiano abbandonando il supporto per questo. Forse anche tirarlo in futuro - https://github.com / dotnet / apireviews / tree / master / 2015-07-14-securestring .

  

Dovremmo rimuovere la crittografia da SecureString su tutte le piattaforme in .NET Core - Dovremmo obsoleto SecureString - Probabilmente non dovremmo esporre SecureString in .NET Core

Un altro caso d'uso è quando si lavora con applicazioni di pagamento (POS) e semplicemente non è possibile utilizzare strutture di dati immutabili per archiviare dati sensibili perché si è attenti sviluppatori. Ad esempio: se memorizzerò i dati sensibili delle carte o i metadati di autorizzazione in una stringa immutabile, ci sarebbe sempre il caso in cui questi dati saranno disponibili in memoria per un periodo di tempo significativo dopo che sono stati eliminati. Non posso semplicemente sovrascriverlo. Un altro enorme vantaggio in cui tali dati sensibili vengono conservati in memoria crittografati.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top