Saya mencoba untuk memahami tujuan SecureString .NET. Dari MSDN:
Sebuah instance dari kelas System.String keduanya tidak berubah dan, ketika tidak lagi diperlukan, tidak dapat dijadwalkan secara program untuk pengumpulan sampah; Yaitu, instance hanya-baca setelah dibuat dan tidak mungkin untuk memprediksi kapan instance akan dihapus dari memori komputer. Akibatnya, jika objek String berisi informasi sensitif seperti kata sandi, nomor kartu kredit, atau data pribadi, ada risiko informasi tersebut dapat diungkapkan setelah digunakan karena aplikasi Anda tidak dapat menghapus data dari memori komputer.
Objek SecureString mirip dengan objek String karena memiliki nilai teks. Namun, nilai objek SecureString dienkripsi secara otomatis, dapat dimodifikasi hingga aplikasi Anda menandainya sebagai hanya-baca, dan dapat dihapus dari memori komputer oleh aplikasi Anda atau pengumpul sampah .NET Framework.
Nilai instance dari SecureString secara otomatis dienkripsi ketika instance diinisialisasi atau ketika nilai diubah. Aplikasi Anda dapat membuat instance tidak dapat diubah dan mencegah modifikasi lebih lanjut dengan menggunakan metode MakeReadOnly.
Apakah enkripsi otomatis merupakan hadiah besar?
Dan mengapa saya tidak bisa mengatakan:
SecureString password = new SecureString("password");
dari pada
SecureString pass = new SecureString();
foreach (char c in "password".ToCharArray())
pass.AppendChar(c);
Aspek SecureString apa yang saya lewatkan?
sumber
SecureString
untuk pengembangan baru: github.com/dotnet/platform-compat/blob/master/docs/DE0001.mdJawaban:
Saya akan berhenti menggunakan SecureString. Sepertinya orang-orang PG menjatuhkan dukungan untuk itu. Bahkan mungkin menariknya di masa mendatang - https://github.com/dotnet/apireviews/tree/master/2015-07-07-securestring .
sumber
Beberapa bagian dari kerangka kerja yang saat ini digunakan
SecureString
:System.Windows.Controls.PasswordBox
Kontrol WPF menjaga kata sandi sebagai SecureString secara internal (diekspos sebagai salinanPasswordBox::SecurePassword
)System.Diagnostics.ProcessStartInfo::Password
properti adalahSecureString
X509Certificate2
mengambilSecureString
kata sandiTujuan utamanya adalah mengurangi permukaan serangan, bukan menghilangkannya.
SecureStrings
"disematkan" dalam RAM sehingga Pengumpul Sampah tidak akan memindahkannya atau membuat salinannya. Ini juga memastikan teks biasa tidak akan ditulis ke file Swap atau di dump inti. Enkripsi lebih seperti kebingungan dan tidak akan menghentikan peretas, yang dapat menemukan kunci simetris yang digunakan untuk mengenkripsi dan mendekripsi.Seperti yang dikatakan orang lain, alasan Anda harus membuat
SecureString
karakter-demi-karakter adalah karena kesalahan pertama yang jelas dalam melakukan sebaliknya: Anda mungkin sudah memiliki nilai rahasia sebagai string polos, jadi apa gunanya?SecureString
Ini adalah langkah pertama dalam menyelesaikan masalah Ayam-dan-Telur, jadi meskipun sebagian besar skenario saat ini mengharuskan untuk mengubahnya kembali menjadi string reguler untuk memanfaatkannya sama sekali, keberadaan mereka dalam kerangka kerja sekarang berarti dukungan yang lebih baik bagi mereka dalam masa depan - setidaknya ke titik di mana program Anda tidak harus menjadi tautan yang lemah.sumber
Sunting : Jangan gunakan SecureString
Bimbingan saat ini sekarang mengatakan bahwa kelas tidak boleh digunakan. Detailnya dapat ditemukan di tautan ini: https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md
Dari artikel:
DE0001: SecureString tidak boleh digunakan
Motivasi
SecureString
adalah untuk menghindari menyimpan rahasia dalam memori proses sebagai teks biasa.SecureString
tidak ada sebagai konsep OS.System.String
- masa pakai buffer asli lebih pendek.Rekomendasi
Jangan gunakan
SecureString
untuk kode baru. Saat porting kode ke .NET Core, pertimbangkan bahwa isi array tidak dienkripsi dalam memori.Pendekatan umum berurusan dengan kredensial adalah untuk menghindarinya dan sebaliknya mengandalkan cara lain untuk mengotentikasi, seperti sertifikat atau otentikasi Windows.
Edit Akhir: Ringkasan Asli di bawah ini
Banyak jawaban bagus; inilah sinopsis singkat dari apa yang telah dibahas.
Microsoft telah mengimplementasikan kelas SecureString dalam upaya memberikan keamanan yang lebih baik dengan informasi sensitif (seperti kartu kredit, kata sandi, dll.). Secara otomatis menyediakan:
Saat ini, SecureString terbatas digunakan tetapi mengharapkan adopsi yang lebih baik di masa depan.
Berdasarkan informasi ini, konstruktor dari SecureString tidak boleh hanya mengambil string dan mengirisnya ke char array karena memiliki string yang dieja mengalahkan tujuan SecureString.
Informasi tambahan:
Sunting: Saya merasa sulit untuk memilih jawaban terbaik karena ada banyak informasi bagus; Sayang sekali tidak ada opsi jawaban yang dibantu.
sumber
Jawaban singkat
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
:Catatan : SecureZeroMemory identik dengan
ZeroMemory
, kecuali kompiler tidak akan mengoptimalkannya.Masalahnya adalah bahwa Anda tidak dapat memanggil
ZeroMemory
atauSecureZeroMemory
di dalam. NET. Dan dalam string .NET tidak berubah; Anda bahkan tidak bisa menimpa isi string seperti yang dapat Anda lakukan dalam bahasa lain: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:SecureString memberikan kembali kemampuan yang hilang
Di .NET, Strings tidak dapat dihapus ketika Anda selesai menggunakannya:
Dispose
dari merekaSecureString ada sebagai cara untuk membagikan keamanan string, dan dapat menjamin pembersihan mereka saat Anda membutuhkannya.
Anda mengajukan pertanyaan:
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:
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 :
Anda juga dapat mengubah kata sandi dalam String Koneksi:
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:
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:
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:
seperti dalam:
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:
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.
sumber
Ada beberapa skenario di mana Anda dapat menggunakan SecureString dengan bijaksana dalam versi Framework saat ini. Ini benar-benar hanya berguna untuk berinteraksi dengan API yang tidak dikelola - Anda dapat menyusunnya menggunakan Marshal.SecureStringToGlobalAllocUnicode.
Segera setelah Anda mengonversinya ke / dari System.String, Anda telah mengalahkan tujuannya.
Sampel MSDN menghasilkan SecureString karakter sekaligus dari input konsol dan meneruskan string aman ke API yang tidak dikelola. Ini agak berbelit-belit dan tidak realistis.
Anda mungkin mengharapkan versi .NET masa depan untuk memiliki lebih banyak dukungan untuk SecureString yang akan membuatnya lebih bermanfaat, misalnya:
SecureString Console.ReadLineSecure () atau serupa dengan membaca input konsol ke SecureString tanpa semua kode berbelit-belit dalam sampel.
Penggantian WinForms TextBox yang menyimpan properti TextBox.Text sebagai string yang aman sehingga kata sandi dapat dimasukkan dengan aman.
Ekstensi ke API terkait keamanan untuk memungkinkan kata sandi diteruskan sebagai SecureString.
Tanpa hal di atas, SecureString akan memiliki nilai terbatas.
sumber
Saya percaya alasan mengapa Anda harus melakukan penambahan karakter alih-alih satu instantiasi datar adalah karena di latar belakang meneruskan "kata sandi" ke konstruktor SecureString menempatkan bahwa "kata sandi" string dalam memori mengalahkan tujuan dari string aman.
Dengan menambahkan Anda hanya menempatkan karakter pada satu waktu ke memori yang mungkin tidak berdekatan satu sama lain secara fisik membuatnya lebih sulit untuk merekonstruksi string asli. Saya bisa saja salah di sini, tetapi begitulah dijelaskan kepada saya.
Tujuan kelas adalah untuk mencegah data yang aman dari terkena melalui dump memori atau alat serupa.
sumber
MS menemukan bahwa pada contoh tertentu menyebabkan server (desktop, apa pun) untuk crash ada kalanya lingkungan runtime akan melakukan dump memori yang mengekspos isi dari apa yang ada di memori. Secure String mengenkripsi itu dalam memori untuk mencegah penyerang bisa mengambil konten string.
sumber
Salah satu manfaat besar dari SecureString adalah bahwa ia seharusnya menghindari kemungkinan data Anda disimpan ke disk karena caching halaman. Jika Anda memiliki kata sandi di memori dan kemudian memuat program besar atau kumpulan data, kata sandi Anda mungkin akan ditulis ke file swap saat program Anda paging kehabisan memori. Dengan SecureString, setidaknya data tidak akan berada di disk Anda tanpa batas dalam teks yang jelas.
sumber
Saya kira itu karena string dimaksudkan untuk menjadi aman, yaitu seorang hacker seharusnya tidak dapat membacanya. Jika Anda menginisialisasi dengan string, peretas dapat membaca string asli.
sumber
Nah, seperti yang dinyatakan deskripsi, nilai disimpan terenkripsi, dengan berarti bahwa dump memori proses Anda tidak akan mengungkapkan nilai string (tanpa kerja yang cukup serius).
Alasan Anda tidak bisa hanya membangun SecureString dari string konstan adalah karena Anda akan memiliki versi string yang tidak terenkripsi dalam memori. Membatasi Anda untuk membuat string menjadi beberapa bagian mengurangi risiko memiliki seluruh string dalam memori sekaligus.
sumber
Kasus penggunaan lain adalah ketika Anda bekerja dengan aplikasi pembayaran (POS) dan Anda tidak bisa menggunakan struktur data yang tidak dapat diubah untuk menyimpan data sensitif karena Anda adalah pengembang yang cermat. Misalnya: jika saya akan menyimpan data kartu sensitif atau metadata otorisasi ke string yang tidak dapat diubah, selalu ada kasus ketika data ini akan tersedia dalam memori untuk waktu yang lama setelah dibuang. Saya tidak bisa begitu saja menimpanya. Keuntungan besar lainnya di mana data sensitif seperti itu disimpan dalam memori terenkripsi.
sumber