È risaputo che C # string
è piuttosto insicuro, non è bloccato nella RAM, Garbage Collector può spostarlo, copiarlo, lasciarne più tracce nella RAM e la RAM può essere scambiata ed essere disponibile come un file da leggere, senza menzionare molti altri fatti noti.
Per mitigare questo Microsoft si avvicinò con SecureString
. Il fatto è: qual è il modo corretto di usarlo?
Chiedo questo perché prima o poi dovrai estrarre la stringa interna. E sì, SecureString
ci consente di scrivere un char
alla volta e ci dà alcuni altri utilizzi minori nascondendo il suo segreto, ma a volte abbiamo bisogno dell'intera stringa in una volta o qualcosa del genere. Finora tutte le implementazioni che vedo utilizzano un normale string
alla fine, con il contenuto estratto e decrittografato da SecureString
che penso (o spero) sia evitabile in alcuni casi anche se potrebbe comportare un codice complicato da aggirare un .NET string
.
Nel mio caso, utilizzo una libreria per l'hashing della password denominata BCrypt . Usa un string
regolare per calcolare gli hash, che a mio parere è tutt'altro che ideale. Non ho trovato alcuna libreria che accetti direttamente un SecureString
, quindi non ho molte opzioni ma la uso.
Attualmente eseguo codice come questo:
SecureString password; // This usually comes from a PasswordBox Property
IntPtr passwordBSTR = Marshal.SecureStringToBSTR(password);
string insecurePassword = Marshal.PtrToStringBSTR(passwordBSTR);
Marshal.ZeroFreeBSTR(passwordBSTR);
passwordBSTR = default(IntPtr);
password.Clear();
// Use the insecurePassword....usually as:
bool result = BCrypt.Net.BCrypt.Verify(insecurePassword, user.Password); // This hashes the provided password and compares it with another BCrypt hash.
insecureString = string.Empty; // hoping for the GC to act now, fingers crossed.
// use result and etc...
In questo modo la password% raw% co_de verrà copiata più volte per il metodo string
e probabilmente anche più volte al suo interno.
Questo fa sorgere alcune domande nella mia mente:
1 - Sono BCrypt
stringhe come BSTR
stringhe nel senso della gestione della memoria? Sono bloccate nella RAM e posso manipolarle e cancellarle come ritengo opportuno così sarà più sicuro di usarli in C # o di interoplo con un codice C ++ in modo da poter eliminare molte delle mie manipolazioni .NET C
(come verificare se la stringa della password è nullo o bianca o ha la lunghezza corretta o ha la password desiderata forza)?
2 - Se la risposta n. 1 della domanda è "sì" allora dovrei investire un po 'di tempo per passare la stringa BSTR a un codice C ++ interop per calcolare il suo hash e verificare?
3 - Il mio codice successivo è corretto o mi manca qualcosa su string
manipolazione?
Giusto per essere chiari: il mio intento principale con questa domanda è valutare se dovrei passare tutto il mio codice di gestione password al C ++ dal mio C # (probabilmente usando C ++ / CLI o interop) per ottenere un codice più sicuro di quello che C # ha da offrire. Questo scenario mi riguarda davvero per l'hashing delle stringhe di password in cui sono state create più stringhe e copiate con le informazioni segrete dell'utente sparse in tutta la RAM.
Ad esempio: potrei creare un metodo come:
public string SecureHash(SecureString password)
E questo metodo estrarrà il valore SecureString
e lo passerà come una stringa SecureString
(o altra opzione di estrazione, onestamente non conosco i vantaggi tra di loro) per un metodo di hashing C ++, così possiamo controllare tutto i luoghi in cui la nostra password si trova in memoria.
Chiedo a questo di non avere un'enorme opera di refactoring del mio codice e alla fine scopro che è stato tutto inutile perché stavo usando BSTR
in modo errato tutto il tempo e ci sono già soluzioni per questo, o un falso senso di sicurezza, come accade a volte, poiché non sono a conoscenza di come le stringhe SecureStrings
siano implementate in memoria o l'altro BSTR
opzioni di estrazione (Unicode, ANSI ed ecc.)