Jangan ragu untuk mengoreksi saya jika asumsi saya salah di sini, tetapi izinkan saya menjelaskan mengapa saya bertanya.
Diambil dari MSDN, a SecureString
:
Merupakan teks yang harus dijaga kerahasiaannya. Teks dienkripsi untuk privasi saat digunakan, dan dihapus dari memori komputer ketika tidak lagi diperlukan.
Saya mendapatkan ini, sangat masuk akal untuk menyimpan kata sandi atau informasi pribadi lainnya di SecureString
atas System.String
, karena Anda dapat mengontrol bagaimana dan kapan itu sebenarnya disimpan dalam memori, karena a System.String
:
keduanya kekal 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.
Namun, dalam kasus aplikasi GUI (misalnya, klien ssh), SecureString
harus dibangun dari a System.String
. Semua kontrol teks menggunakan string sebagai tipe data yang mendasarinya .
Jadi, ini berarti bahwa setiap kali pengguna menekan kunci, string lama yang ada di sana dibuang, dan string baru dibangun untuk mewakili nilai di dalam kotak teks, bahkan jika menggunakan topeng kata sandi. Dan kita tidak dapat mengontrol kapan atau jika salah satu dari nilai-nilai itu dibuang dari memori .
Sekarang saatnya untuk masuk ke server. Tebak apa? Anda perlu memberikan string pada koneksi untuk otentikasi . Jadi mari kita konversikan SecureString
menjadi System.String
.... dan sekarang kita memiliki string di heap tanpa ada cara untuk memaksanya melalui pengumpulan sampah (atau menulis 0 ke buffernya).
Maksud saya adalah : tidak peduli apa yang Anda lakukan, suatu tempat di sepanjang garis, yang SecureString
sedang akan akan diubah menjadi System.String
, berarti setidaknya akan eksis di tumpukan di beberapa titik (tanpa jaminan pengumpulan sampah).
Maksud saya bukanlah : apakah ada cara mengelak mengirim string ke koneksi ssh, atau menghindari memiliki kontrol menyimpan string (membuat kontrol kustom). Untuk pertanyaan ini, Anda dapat mengganti "koneksi ssh" dengan "formulir masuk", "formulir pendaftaran", "formulir pembayaran", "makanan-Anda-akan-memberi makan formulir anak anjing-tetapi-bukan-anak-Anda", dll.
- Jadi, pada titik apa menggunakan
SecureString
sebenarnya menjadi praktis? - Apakah ini sepadan dengan waktu pengembangan ekstra untuk sepenuhnya menghapus penggunaan
System.String
objek? - Apakah seluruh titik
SecureString
untuk hanya mengurangi jumlah waktu yangSystem.String
ada di tumpukan (mengurangi risiko pindah ke file swap fisik)? - Jika penyerang sudah memiliki sarana untuk inspeksi tumpukan, maka kemungkinan besar dia (A) sudah memiliki sarana untuk membaca penekanan tombol, atau (B) secara fisik memiliki mesin ... Jadi akan menggunakan
SecureString
mencegah dia dari mendapatkan ke data lagian? - Apakah ini hanya "keamanan melalui ketidakjelasan"?
Maaf jika saya mengajukan pertanyaan terlalu tebal, rasa ingin tahu hanya membuat saya lebih baik. Merasa bebas untuk menjawab salah satu atau semua pertanyaan saya (atau memberi tahu saya bahwa asumsi saya sepenuhnya salah). :)
SecureString
itu bukan string yang aman. Ini hanyalah cara untuk mengurangi jendela waktu di mana seseorang dapat memeriksa memori Anda dan berhasil mendapatkan data sensitif. Ini bukan antipeluru dan tidak dimaksudkan untuk itu. Tetapi poin yang Anda naikkan sangat valid. Terkait: stackoverflow.com/questions/14449579/…Jawaban:
Sebenarnya ada kegunaan yang sangat praktis
SecureString
.Apakah Anda tahu sudah berapa kali saya melihat skenario seperti itu? (jawabannya adalah: banyak!):
RedGate
perangkat lunak yang bisa menangkap "nilai" variabel lokal jika ada pengecualian, sangat berguna. Padahal, saya bisa membayangkan bahwa itu akan masuk "string password" secara tidak sengaja.Apakah Anda tahu cara menghindari semua masalah ini?
SecureString
. Biasanya memastikan Anda tidak membuat kesalahan konyol seperti itu. Bagaimana cara menghindarinya? Dengan memastikan bahwa kata sandi dienkripsi dalam memori yang tidak dikelola dan nilai sebenarnya hanya dapat diakses ketika Anda 90% yakin dengan apa yang Anda lakukan.Dalam arti,
SecureString
bekerja cukup mudah:1) Semuanya dienkripsi
2) Panggilan pengguna
AppendChar
3) Dekripsi segala sesuatu dalam MEMORI TIDAK DITETAPKAN dan tambahkan karakter
4) Enkripsi semuanya lagi dalam MEMORY UNMANAGED.
Bagaimana jika pengguna memiliki akses ke komputer Anda? Apakah virus bisa mendapatkan akses ke semua
SecureStrings
? Iya. Yang perlu Anda lakukan adalah menghubungkan diri AndaRtlEncryptMemory
ketika memori sedang didekripsi, Anda akan mendapatkan lokasi alamat memori yang tidak dienkripsi, dan membacanya. Voila! Bahkan, Anda bisa membuat virus yang akan terus memindai penggunaanSecureString
dan mencatat semua kegiatan dengannya. Saya tidak mengatakan itu akan menjadi tugas yang mudah, tetapi itu bisa dilakukan. Seperti yang Anda lihat, "kekuatan"SecureString
sepenuhnya hilang setelah ada pengguna / virus di sistem Anda.Anda memiliki beberapa poin dalam posting Anda. Tentu, jika Anda menggunakan beberapa kontrol UI yang menyimpan "string password" secara internal, menggunakan aktual
SecureString
tidak terlalu berguna. Meskipun, tetap saja, itu bisa melindungi dari kebodohan yang saya sebutkan di atas.Juga, seperti yang telah dicatat oleh orang lain, WPF mendukung PasswordBox yang digunakan secara
SecureString
internal melalui properti SecurePassword -nya .Intinya adalah; jika Anda memiliki data sensitif (kata sandi, kartu kredit, ..), gunakan
SecureString
. Inilah yang mengikuti Kerangka C #. Misalnya,NetworkCredential
kelas menyimpan kata sandi sebagaiSecureString
. Jika Anda melihat ini , Anda dapat melihat ~ 80 penggunaan berbeda dalam .NET framework ofSecureString
.Ada banyak kasus ketika Anda harus mengonversi
SecureString
ke string, karena beberapa API mengharapkannya.Masalah yang biasa terjadi adalah:
Anda mengangkat poin bagus: apa yang terjadi ketika
SecureString
dikonversi kestring
? Ini hanya dapat terjadi karena poin pertama. Misalnya API tidak tahu bahwa itu data sensitif. Saya pribadi tidak melihat itu terjadi. Mendapatkan string dari SecureString tidak sesederhana itu.Itu tidak sederhana karena alasan sederhana ; itu tidak pernah dimaksudkan untuk membiarkan pengguna mengkonversi SecureString ke string, seperti yang Anda nyatakan: GC akan menendang. Jika Anda melihat diri Anda melakukan itu, Anda perlu mundur dan bertanya pada diri sendiri: Mengapa saya melakukan ini, atau apakah saya benar-benar membutuhkan ini kenapa?
Ada satu kasus menarik yang saya lihat. Yaitu, fungsi WinApi LogonUser mengambil LPTSTR sebagai kata sandi, yang berarti Anda harus menelepon
SecureStringToGlobalAllocUnicode
. Itu pada dasarnya memberi Anda kata sandi tidak terenkripsi yang hidup di memori yang tidak dikelola. Anda harus menyingkirkannya segera setelah selesai:Anda selalu dapat memperluas
SecureString
kelas dengan metode ekstensi, sepertiToEncryptedString(__SERVER__PUBLIC_KEY)
, yang memberi Andastring
contohSecureString
yang dienkripsi menggunakan kunci publik server. Hanya server yang dapat mendekripsi itu. Masalah terpecahkan: Pengumpulan Sampah tidak akan pernah melihat string "asli", karena Anda tidak pernah mengeksposnya dalam memori yang dikelola. Inilah yang dilakukan diPSRemotingCryptoHelper
(EncryptSecureStringCore(SecureString secureString)
).Dan sebagai sesuatu yang sangat berhubungan: Mono SecureString tidak mengenkripsi sama sekali . Implementasinya telah dikomentari karena ..menunggu itu .. "Ini entah bagaimana menyebabkan kerusakan tes nunit" , yang membawa ke poin terakhir saya:
SecureString
tidak didukung di mana-mana. Jika platform / arsitektur tidak mendukungSecureString
, Anda akan mendapatkan pengecualian. Ada daftar platform yang didukung dalam dokumentasi.sumber
SecureString
akan jauh lebih praktis jika ada mekanisme untuk mengakses karakter individu daripadanya. Efisiensi untuk mekanisme semacam itu dapat ditingkatkan dengan memiliki tipe structSecureStringTempBuffer
tanpa anggota publik, yang dapat diteruskanref
ke metodeSecureString
"baca satu karakter" [jika enkripsi / dekripsi diproses dalam potongan 8 karakter, struktur seperti itu dapat menyimpan data untuk 8 karakter dan lokasi karakter pertama dari dalamSecureString
].SecureString
harus digunakan sepenuhnya melalui tumpukan.EngineSettings
di Metode Ekstensi Anda?SecureString
tidak boleh digunakan untuk pengembangan baru ?Ada beberapa masalah dalam asumsi Anda.
Pertama-tama kelas SecureString tidak memiliki konstruktor String. Untuk membuat satu, Anda mengalokasikan objek dan kemudian menambahkan karakter.
Dalam kasus GUI atau konsol, Anda dapat dengan mudah melewatkan setiap tombol yang ditekan ke string yang aman.
Kelas dirancang sedemikian rupa sehingga Anda tidak bisa, secara tidak sengaja, mengakses nilai yang disimpan. Ini berarti Anda tidak dapat memperoleh
string
kata sandi secara langsung darinya.Jadi untuk menggunakannya, misalnya, untuk mengautentikasi melalui web, Anda harus menggunakan kelas yang tepat yang juga aman.
Dalam .NET framework Anda memiliki beberapa kelas yang dapat menggunakan SecureString
(lebih)
Untuk menyimpulkan, kelas SecureString dapat bermanfaat, tetapi membutuhkan lebih banyak perhatian dari pengembang.
Semua ini, dengan contoh-contoh, dijelaskan dengan baik dalam dokumentasi MSDN tentang SecureString
sumber
SecureString
melalui jaringan tanpa membuat serial menjadistring
? Saya pikir poin OP pertanyaannya adalah bahwa ada saatnya Anda ingin benar-benar menggunakan nilai yang disimpan dalam aSecureString
, yang berarti Anda harus mengeluarkannya dari sana, dan itu tidak lagi aman. Di semua Framework Class Library, sebenarnya tidak ada metode yang menerimaSecureString
input langsung sebagai (sejauh yang saya bisa lihat), jadi apa gunanya memegang nilai di dalamSecureString
di tempat pertama?char[]
dan mengirimkan masing-masingchar
melalui soket - tidak menciptakan objek yang dapat dikumpulkan sampah dalam proses.SecureString berguna jika:
Anda membangunnya karakter demi karakter (mis. Dari input konsol) atau mendapatkannya dari API yang tidak dikelola
Anda menggunakannya dengan meneruskannya ke API yang tidak dikelola (SecureStringToBSTR).
Jika Anda pernah mengonversinya menjadi string yang dikelola, Anda telah mengalahkan tujuannya.
UPDATE sebagai tanggapan terhadap komentar
Setelah dikonversi ke BSTR, komponen yang tidak dikelola yang menggunakan BSTR dapat mem-nolkan memori. Memori yang tidak dikelola lebih aman dalam arti dapat diatur ulang dengan cara ini.
Namun, ada sangat sedikit, API di .NET Framework yang mendukung SecureString, jadi Anda benar untuk mengatakan bahwa itu memiliki nilai yang sangat terbatas hari ini.
Kasus penggunaan utama yang akan saya lihat adalah dalam aplikasi klien yang mengharuskan pengguna untuk memasukkan kode atau kata sandi yang sangat sensitif. Input pengguna dapat digunakan karakter demi karakter untuk membangun SecureString, maka ini dapat diteruskan ke API yang tidak dikelola, yang memberikan nilai nol pada BSTR yang diterimanya setelah menggunakannya. Setiap dump memori berikutnya tidak akan mengandung string sensitif.
Dalam aplikasi server sulit untuk melihat di mana itu akan berguna.
PEMBARUAN 2
Salah satu contoh .NET API yang menerima SecureString adalah konstruktor ini untuk kelas X509Certificate . Jika Anda melakukan spelunk dengan ILSpy atau yang serupa, Anda akan melihat bahwa SecureString secara internal dikonversi ke buffer yang tidak dikelola (
Marshal.SecureStringToGlobalAllocUnicode
), yang kemudian di-zeroed ketika selesai dengan (Marshal.ZeroFreeGlobalAllocUnicode
).sumber
SecureString
input sebagai, apa yang akan mereka gunakan? Anda harus selalu mengonversi kembali kestring
cepat atau lambat (atauBSTR
seperti yang Anda sebutkan, yang sepertinya tidak lebih aman). Jadi mengapa harus repot-repotSecureString
?Microsoft tidak merekomendasikan untuk menggunakan
SecureString
kode yang lebih baru.Dari dokumentasi Kelas SecureString :
Yang merekomendasikan:
sumber
Seperti yang telah Anda identifikasi dengan benar,
SecureString
menawarkan satu keunggulan spesifik atasstring
: penghapusan deterministik. Ada dua masalah dengan fakta ini:SecureString
. Ini berarti bahwa Anda harus berhati-hati untuk tidak pernah membuat GC-dikelola berubahstring
atau penyangga lainnya yang akan menyimpan informasi sensitif (atau Anda harus melacak yang juga). Dalam praktiknya, ini tidak selalu mudah dicapai, karena banyak API hanya menawarkan cara untuk bekerjastring
, bukanSecureString
. Dan bahkan jika Anda berhasil melakukan semuanya dengan benar ...SecureString
melindungi terhadap jenis serangan yang sangat spesifik (dan bagi sebagian dari mereka, itu bahkan tidak dapat diandalkan). Misalnya,SecureString
tidak memungkinkan Anda untuk mengecilkan jendela waktu di mana penyerang dapat membuang memori proses Anda dan berhasil mengekstrak informasi sensitif (sekali lagi, seperti yang Anda tunjukkan dengan benar), tetapi berharap bahwa jendela itu terlalu kecil untuk penyerang untuk mengambil snapshot dari memori Anda tidak dianggap keamanan sama sekali.Jadi, kapan Anda harus menggunakannya? Hanya ketika Anda bekerja dengan sesuatu yang dapat memungkinkan Anda untuk bekerja dengan
SecureString
semua kebutuhan Anda dan bahkan kemudian Anda harus tetap sadar bahwa ini aman hanya dalam keadaan tertentu.sumber
Teks di bawah ini disalin dari penganalisa kode statis HP Fortify
Abstrak: Metode PassString () di PassGenerator.cs menyimpan data sensitif dengan cara yang tidak aman (yaitu dalam string), sehingga memungkinkan untuk mengekstraksi data dengan memeriksa heap.
Penjelasan: Data sensitif (seperti kata sandi, nomor jaminan sosial, nomor kartu kredit, dll.) Yang tersimpan dalam memori dapat bocor jika disimpan dalam objek String yang dikelola. Objek string tidak disematkan, sehingga pemulung dapat memindahkan objek ini sesuka hati dan meninggalkan beberapa salinan dalam memori. Objek-objek ini tidak dienkripsi secara default, jadi siapa pun yang dapat membaca memori proses akan dapat melihat kontennya. Lebih jauh, jika memori proses 'ditukar ke disk, isi string yang tidak terenkripsi akan ditulis ke file swap. Terakhir, karena objek String tidak dapat diubah, menghapus nilai String dari memori hanya dapat dilakukan oleh pengumpul sampah CLR. Pengumpul sampah tidak diharuskan untuk menjalankan kecuali memori pada CLR rendah, sehingga tidak ada jaminan kapan pengumpulan sampah akan terjadi.
Rekomendasi: Alih-alih menyimpan data sensitif dalam objek seperti Strings, menyimpannya dalam objek SecureString. Setiap objek menyimpan kontennya dalam format terenkripsi dalam memori setiap saat.
sumber
Saya ingin membahas hal ini:
Seorang penyerang mungkin tidak memiliki akses penuh ke komputer dan aplikasi tetapi dapat memiliki sarana untuk mengakses beberapa bagian dari memori proses. Biasanya disebabkan oleh bug seperti buffer overruns ketika input yang dibangun secara khusus dapat menyebabkan aplikasi mengekspos atau menimpa beberapa bagian dari memori.
Memori bocor HeartBleed
Ambil Heartbleed misalnya. Permintaan yang dibuat secara khusus dapat menyebabkan kode mengekspos bagian acak dari memori proses ke penyerang. Seorang penyerang dapat mengekstraksi sertifikat SSL dari memori, namun satu-satunya yang ia butuhkan hanyalah menggunakan permintaan yang cacat.
Di dunia kode terkelola, buffer overruns menjadi masalah jauh lebih jarang. Dan dalam kasus WinForms, data sudah disimpan dengan cara yang tidak aman dan Anda tidak dapat melakukan apa-apa. Ini membuat perlindungan dengan
SecureString
sangat tidak berguna.Namun, GUI dapat diprogram untuk digunakan
SecureString
, dan dalam kasus semacam itu mengurangi ketersediaan jendela kata sandi di memori bisa sia-sia. Misalnya, PasswordBox.SecurePassword dari WPF adalah tipeSecureString
.sumber
Beberapa waktu yang lalu saya harus membuat antarmuka ac # terhadap gateway pembayaran kartu kredit java dan satu membutuhkan enkripsi kunci komunikasi aman yang kompatibel. Karena implementasi Java agak spesifik dan saya harus bekerja dengan data yang dilindungi dengan cara tertentu.
Saya menemukan desain ini cukup mudah digunakan dan lebih mudah daripada bekerja dengan SecureString ... bagi mereka yang suka menggunakan ... merasa bebas, tidak ada batasan hukum :-). Perhatikan bahwa kelas-kelas ini bersifat internal, Anda mungkin perlu mempublikasikannya.
sumber