Kısa cevap
neden sadece söyleyemem:
SecureString password = new SecureString("password");
Çünkü şimdi password
hafızanız var; tamamen silmenin bir yolu yok - ki bu tamamen SecureString'in noktası .
Uzun cevap
SecureString'in var olmasının nedeni , ZeroMemory'yi işiniz bittiğinde hassas verileri silmek için kullanamamanızdır . CLR nedeniyle var olan bir sorunu çözmek için var .
Normal bir yerel uygulamada şunları çağırırsınız SecureZeroMemory
:
Bir bellek bloğunu sıfırlarla doldurur.
Not : SecureZeroMemory ile aynıdır ZeroMemory
, ancak derleyici onu optimize etmez.
Sorun olduğunu olamaz diyoruz ZeroMemory
ya SecureZeroMemory
iç .NET. Ve .NET dizeleri değişmez; diğer dillerde olduğu gibi dizenin içeriğinin üzerine bile yazamazsınız :
//Wipe out the password
for (int i=0; i<password.Length; i++)
password[i] = \0;
Peki ne yapabilirsin? İşimiz bittiğinde .NET'te bir şifreyi veya kredi kartı numarasını bellekten silme yeteneğini nasıl sağlarız?
Bu yapılabilir tek yolu bazı dizeyi yerleştirmek olacaktır yerli bellek bloğu, olabilir o zaman diyoruz ZeroMemory
. Yerel bellek nesnesi:
- bir BSTR
- bir HGLOBAL
- CoTaskMem yönetilmeyen bellek
SecureString kayıp yeteneğini geri verir
.NET'te, işiniz bittiğinde Dizeler silinemez:
- değişmezler; içeriklerinin üzerine yazamazsın
Dispose
onlardan yapamazsın
- temizliği çöp toplayıcının insafına
SecureString, dizelerin güvenliğini aşmanın ve gerektiğinde bunların temizlenmesini garanti edebilmenin bir yolu olarak mevcuttur.
Soruyu sordunuz:
neden sadece söyleyemem:
SecureString password = new SecureString("password");
Çünkü şimdi password
hafızanız var; silmek için bir yol yok. CLR bu belleği yeniden kullanmaya karar verene kadar orada sıkışmış. Bizi başladığımız yere geri koydunuz; şifresini kaldıramadığımız ve bellek dökümü (veya İşlem Monitörü) şifreyi görebildiği çalışan bir uygulama.
SecureString, şifrelenmiş dizeyi bellekte depolamak için Veri Koruma API'sini kullanır; bu şekilde dize, takas dosyalarında, çökme dökümlerinde veya hatta yerel değişkenler penceresinde, bir meslektaşınızın sizin ihtiyacınıza bakmasıyla mevcut olmaz.
Şifreyi nasıl okurum?
O zaman soru şu: dize ile nasıl etkileşim kurabilirim? Kesinlikle yok bir yöntem gibi istiyorum:
String connectionString = secureConnectionString.ToString()
çünkü şimdi başladığınız yere geri döndünüz - kurtulamayacağınız bir şifre. Sen istediğiniz zorlamak doğru duyarlı dize işlemek için geliştiriciler - bu yüzden o olabilir bellekten silinmelidir.
Bu nedenle .NET, SecureString'i yönetilmeyen bir belleğe toplamak için üç kullanışlı yardımcı işlev sunar:
Dizeyi yönetilmeyen bir bellek blobuna dönüştürür, işler ve sonra yeniden silersiniz.
Bazı API'lar SecureStrings'i kabul eder . Örneğin, ADO.net 4.5'te SqlConnection.Credential bir set SqlCredential alır :
SqlCredential cred = new SqlCredential(userid, password); //password is SecureString
SqlConnection conn = new SqlConnection(connectionString);
conn.Credential = cred;
conn.Open();
Ayrıca bir Bağlantı Dizesi içindeki parolayı da değiştirebilirsiniz:
SqlConnection.ChangePassword(connectionString, cred, newPassword);
Ve .NET içinde uyumluluk amacıyla düz bir String'i kabul etmeye devam ettikleri, daha sonra hızlı bir şekilde bir SecureString'e dönüştürdüğü birçok yer var.
SecureString'e metin nasıl eklenir?
Bu hala sorunu bırakıyor:
İlk etapta SecureString'e nasıl şifre alabilirim?
Zor olan budur ama asıl mesele sizi güvenlik hakkında düşünmeye itmektir.
Bazen işlevsellik sizin için zaten sağlanmıştır. Örneğin, WPF PasswordBox denetimi size girilen şifreyi bir SecureString olarak doğrudan döndürebilir :
Şu anda elinde bulunan şifreyi alır PasswordBox bir şekilde SecureString .
Bu yardımcı olur, çünkü ham bir dizenin etrafından geçtiğiniz her yerde, artık SecureString'in String ile uyumlu olmadığından şikayet eden tip sisteminiz var. SecureString'inizi normal dizeye dönüştürmek zorunda kalmadan önce olabildiğince uzun gitmek istersiniz.
Bir SecureString'i dönüştürmek yeterince kolaydır:
- SecureStringToBSTR
- PtrToStringBSTR
de olduğu gibi:
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;
}
Sadece bunu yapmanı istemiyorlar.
Ancak bir dizeyi SecureString'e nasıl alabilirim? Yapmanız gereken ilk şey bir String'de bir parolaya sahip olmaktan vazgeçmektir . Başka bir şeye sahip olmanız gerekiyordu . Bir Char[]
dizi bile yardımcı olacaktır.
İşte o zaman her karakteri ekleyebilir ve işiniz bittiğinde düz metni silebilirsiniz:
for (int i=0; i < PasswordArray.Length; i++)
{
password.AppendChar(PasswordArray[i]);
PasswordArray[i] = (Char)0;
}
Parolanızı silebileceğiniz bir bellekte saklamanız gerekir. Buradan SecureString'e yükleyin.
tl; dr: ZeroMemory eşdeğerini sağlamak için SecureString var .
Bazı kişiler , bir cihaz kilitlendiğinde kullanıcının şifresini bellekten silmenin veya kimlik doğrulaması yapıldıktan sonra tuş vuruşlarını bellekten silmenin önemini görmez . Bu kişiler SecureString kullanmıyor.
SecureString
yeni geliştirme önermiyor