Jawaban singkat
mengapa saya tidak bisa mengatakan:
SecureString password = new SecureString("password");
Karena sekarang Anda ada password
dalam memori; tanpa ada cara untuk menghapusnya - yang merupakan titik aman dari SecureString .
Jawaban panjang
Alasan SecureString ada adalah karena Anda tidak dapat menggunakan ZeroMemory untuk menghapus data sensitif ketika Anda selesai menggunakannya. Itu ada untuk memecahkan masalah yang ada karena CLR.
Dalam aplikasi asli biasa Anda akan menelepon SecureZeroMemory
:
Mengisi satu blok memori dengan nol.
Catatan : SecureZeroMemory identik dengan ZeroMemory
, kecuali kompiler tidak akan mengoptimalkannya.
Masalahnya adalah bahwa Anda tidak dapat memanggil ZeroMemory
atau SecureZeroMemory
di dalam. NET. Dan dalam string .NET tidak berubah; Anda bahkan tidak bisa menimpa isi string seperti yang dapat Anda lakukan dalam bahasa lain:
//Wipe out the password
for (int i=0; i<password.Length; i++)
password[i] = \0;
Jadi apa yang bisa kamu lakukan? Bagaimana kami menyediakan kemampuan dalam .NET untuk menghapus kata sandi, atau nomor kartu kredit dari memori ketika kami selesai melakukannya?
Satu-satunya cara yang bisa dilakukan adalah menempatkan string di beberapa blok memori asli , di mana Anda dapat menelepon ZeroMemory
. Objek memori asli seperti:
- sebuah BSTR
- sebuah HGLOBAL
- Memori tidak dikelola CoTaskMem
SecureString memberikan kembali kemampuan yang hilang
Di .NET, Strings tidak dapat dihapus ketika Anda selesai menggunakannya:
- mereka tidak berubah; Anda tidak dapat menimpa isinya
- kamu tidak bisa
Dispose
dari mereka
- pembersihan mereka adalah pada belas kasihan pemulung
SecureString ada sebagai cara untuk membagikan keamanan string, dan dapat menjamin pembersihan mereka saat Anda membutuhkannya.
Anda mengajukan pertanyaan:
mengapa saya tidak bisa mengatakan:
SecureString password = new SecureString("password");
Karena sekarang Anda ada password
dalam memori; tanpa cara untuk menghapusnya. Terjebak di sana sampai CLR memutuskan untuk menggunakan kembali memori itu. Anda telah menempatkan kami kembali di tempat kami mulai; aplikasi yang berjalan dengan kata sandi yang tidak dapat kami singkirkan, dan tempat penyimpanan memori (atau Pemantau Proses) dapat melihat kata sandi.
SecureString menggunakan API Perlindungan Data untuk menyimpan string yang dienkripsi dalam memori; dengan cara itu string tidak akan ada di swapfiles, crash dumps, atau bahkan di jendela variabel lokal dengan seorang kolega yang melihat Anda seharusnya.
Bagaimana saya membaca kata sandi?
Lalu pertanyaannya: bagaimana cara saya berinteraksi dengan string? Anda benar - benar tidak menginginkan metode seperti:
String connectionString = secureConnectionString.ToString()
karena sekarang Anda segera kembali ke tempat Anda memulai - kata sandi yang tidak dapat Anda singkirkan. Anda ingin memaksa pengembang untuk menangani string sensitif dengan benar - sehingga dapat dihapus dari memori.
Itulah sebabnya .NET menyediakan tiga fungsi penolong yang berguna untuk menyusun SecureString menjadi memori yang tidak dikelola:
Anda mengubah string menjadi gumpalan memori yang tidak dikelola, menanganinya, dan kemudian menghapusnya lagi.
Beberapa API menerima SecureStrings . Sebagai contoh di ADO.net 4.5 SqlConnection.Credential mengambil set SqlCredential :
SqlCredential cred = new SqlCredential(userid, password); //password is SecureString
SqlConnection conn = new SqlConnection(connectionString);
conn.Credential = cred;
conn.Open();
Anda juga dapat mengubah kata sandi dalam String Koneksi:
SqlConnection.ChangePassword(connectionString, cred, newPassword);
Dan ada banyak tempat di dalam. NET di mana mereka terus menerima String polos untuk tujuan kompatibilitas, kemudian dengan cepat mengubahnya menjadi SecureString.
Bagaimana cara memasukkan teks ke dalam SecureString?
Ini masih menyisakan masalah:
Bagaimana cara saya mendapatkan kata sandi ke dalam SecureString?
Ini tantangannya, tetapi intinya adalah membuat Anda memikirkan keamanan.
Terkadang fungsionalitas sudah disediakan untuk Anda. Misalnya, kontrol WPF PasswordBox dapat mengembalikan kata sandi yang Anda masukkan sebagai SecureString secara langsung:
Mendapat kata sandi yang saat ini dipegang oleh PasswordBox sebagai SecureString .
Ini membantu karena di mana-mana Anda dulu menyebarkan string mentah, Anda sekarang memiliki sistem tipe yang mengeluh bahwa SecureString tidak kompatibel dengan String. Anda ingin pergi selama mungkin sebelum harus mengubah SecureString Anda kembali ke string biasa.
Mengonversi SecureString cukup mudah:
- SecureStringToBSTR
- PtrToStringBSTR
seperti dalam:
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;
}
Mereka hanya benar-benar tidak ingin Anda melakukannya.
Tapi bagaimana cara mendapatkan string ke SecureString? Yang perlu Anda lakukan adalah berhenti memasukkan kata sandi dalam sebuah String . Anda perlu memilikinya di sesuatu yang lain. Bahkan sebuah Char[]
array akan sangat membantu.
Saat itulah Anda dapat menambahkan setiap karakter dan menghapus plaintext ketika Anda selesai:
for (int i=0; i < PasswordArray.Length; i++)
{
password.AppendChar(PasswordArray[i]);
PasswordArray[i] = (Char)0;
}
Anda perlu kata sandi Anda disimpan di beberapa memori yang dapat Anda hapus. Masukkan ke dalam SecureString dari sana.
tl; dr: SecureString ada untuk memberikan yang setara dengan ZeroMemory .
Beberapa orang tidak melihat gunanya menghapus kata sandi pengguna dari memori ketika perangkat terkunci , atau menghapus penekanan tombol dari memori setelah mereka diautentikasi . Orang-orang itu tidak menggunakan SecureString.
SecureString
untuk pengembangan baru: github.com/dotnet/platform-compat/blob/master/docs/DE0001.md