Apakah SecureString pernah praktis dalam aplikasi C #?

224

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 SecureStringatas 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 SecureStringmenjadi 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 SecureStringsedang 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 SecureStringsebenarnya menjadi praktis?
  • Apakah ini sepadan dengan waktu pengembangan ekstra untuk sepenuhnya menghapus penggunaan System.Stringobjek?
  • Apakah seluruh titik SecureStringuntuk hanya mengurangi jumlah waktu yang System.Stringada 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 SecureStringmencegah 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). :)

Steven Jeffries
sumber
25
Ingatlah bahwa SecureStringitu 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/…
Theodoros Chatzigiannakis
1
@TheodorosChatzigiannakis, ya, itu yang saya kira. Saya hanya menghabiskan sepanjang hari hari ini memeras otak saya untuk mencoba mencari cara aman untuk menyimpan kata sandi untuk masa pakai aplikasi, dan itu hanya membuat saya bertanya-tanya, apakah itu layak?
Steven Jeffries
1
Mungkin tidak sepadan. Tetapi, sekali lagi, Anda mungkin bertahan melawan skenario ekstrem. Ekstrem bukan dalam arti bahwa tidak mungkin bagi seseorang untuk mendapatkan akses semacam ini ke komputer Anda, tetapi dalam arti bahwa jika seseorang mendapatkan akses semacam ini, komputer dianggap (untuk semua maksud dan tujuan) dikompromikan dan saya tidak Saya pikir tidak ada bahasa atau teknik apa pun yang dapat Anda gunakan untuk mempertahankan diri sepenuhnya.
Theodoros Chatzigiannakis
8
Ini melindungi terhadap kata sandi yang terlihat selama bertahun - tahun , lama setelah semua orang berhenti berpikir mungkin ada masalah. Pada hard drive yang dibuang, disimpan dalam file paging. Menggosok memori sehingga peluang untuk ini rendah adalah penting, tidak dapat melakukannya dengan System.String karena tidak dapat diubah. Dibutuhkan infrastruktur yang beberapa program saat ini memiliki akses ke, interop dengan kode asli sehingga metode Marshal.SecureStringXxx () berguna semakin langka. Atau cara yang layak untuk meminta pengguna untuk itu :)
Hans Passant
1
SecureString adalah teknik keamanan yang mendalam. Pertukaran antara biaya pengembangan dan keuntungan keamanan tidak menguntungkan di sebagian besar situasi. Ada beberapa kasus penggunaan yang baik untuk itu.
usr

Jawaban:

237

Sebenarnya ada kegunaan yang sangat praktis SecureString.

Apakah Anda tahu sudah berapa kali saya melihat skenario seperti itu? (jawabannya adalah: banyak!):

  • Kata sandi muncul dalam file log secara tidak sengaja.
  • Kata sandi ditampilkan di suatu tempat - begitu GUI menampilkan baris perintah aplikasi yang sedang dijalankan, dan baris perintah terdiri dari kata sandi. Ups .
  • Menggunakan memori profiler ke perangkat lunak profil dengan kolega Anda. Rekan kerja melihat kata sandi Anda di memori. Kedengarannya tidak nyata? Tidak semuanya.
  • Saya pernah menggunakan RedGateperangkat 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.
  • Sebuah dump dump yang mencakup kata sandi string.

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, SecureStringbekerja 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 Anda RtlEncryptMemoryketika memori sedang didekripsi, Anda akan mendapatkan lokasi alamat memori yang tidak dienkripsi, dan membacanya. Voila! Bahkan, Anda bisa membuat virus yang akan terus memindai penggunaan SecureStringdan mencatat semua kegiatan dengannya. Saya tidak mengatakan itu akan menjadi tugas yang mudah, tetapi itu bisa dilakukan. Seperti yang Anda lihat, "kekuatan" SecureStringsepenuhnya 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 SecureStringtidak 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 SecureStringinternal melalui properti SecurePassword -nya .

Intinya adalah; jika Anda memiliki data sensitif (kata sandi, kartu kredit, ..), gunakan SecureString. Inilah yang mengikuti Kerangka C #. Misalnya, NetworkCredentialkelas menyimpan kata sandi sebagai SecureString. Jika Anda melihat ini , Anda dapat melihat ~ 80 penggunaan berbeda dalam .NET framework of SecureString.

Ada banyak kasus ketika Anda harus mengonversi SecureStringke string, karena beberapa API mengharapkannya.

Masalah yang biasa terjadi adalah:

  1. API adalah GENERIC. Tidak tahu ada data sensitif.
  2. API tahu bahwa itu berurusan dengan data sensitif dan menggunakan "string" - itu hanya desain yang buruk.

Anda mengangkat poin bagus: apa yang terjadi ketika SecureStringdikonversi ke string? 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:

// Marshal the SecureString to unmanaged memory.
IntPtr rawPassword = Marshal.SecureStringToGlobalAllocUnicode(password);
try
{
   //...snip...
}
finally 
{
   // Zero-out and free the unmanaged string reference.
   Marshal.ZeroFreeGlobalAllocUnicode(rawPassword);
}

Anda selalu dapat memperluas SecureStringkelas dengan metode ekstensi, seperti ToEncryptedString(__SERVER__PUBLIC_KEY), yang memberi Anda stringcontoh SecureStringyang 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 di PSRemotingCryptoHelper( 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:

SecureStringtidak didukung di mana-mana. Jika platform / arsitektur tidak mendukung SecureString, Anda akan mendapatkan pengecualian. Ada daftar platform yang didukung dalam dokumentasi.

Erti-Chris Eelmaa
sumber
Saya akan berpikir SecureStringakan jauh lebih praktis jika ada mekanisme untuk mengakses karakter individu daripadanya. Efisiensi untuk mekanisme semacam itu dapat ditingkatkan dengan memiliki tipe struct SecureStringTempBuffertanpa anggota publik, yang dapat diteruskan refke metode SecureString"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 dalam SecureString].
supercat
2
Saya menandai ini di setiap audit kode sumber yang saya lakukan. Ini juga harus diulangi bahwa jika Anda menggunakannya SecureStringharus digunakan sepenuhnya melalui tumpukan.
Casey
1
Saya menerapkan ekstensi .ToEncryptedString () tetapi dengan menggunakan sertifikat. Maukah Anda memeriksanya dan beri tahu saya jika saya melakukan ini semua salah. Saya berharap yang aman engouhg gist.github.com/sturlath/99cfbfff26e0ebd12ea73316d0843330
Sturla
@Sturla - Apa yang ada EngineSettingsdi Metode Ekstensi Anda?
InteXX
15

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 stringkata 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

  • Kontrol Kata Sandi WPF menyimpan kata sandi sebagai SecureString secara internal.
  • Properti System.Diagnostics.ProcessInfo Password adalah SecureString.
  • Konstruktor untuk X509Certificate2 mengambil SecureString untuk kata sandi.

(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

Damian Leszczyński - Vash
sumber
10
Saya tidak begitu mengerti paragraf ketiga hingga terakhir dari jawaban Anda. Bagaimana cara Anda mentransfer SecureStringmelalui jaringan tanpa membuat serial menjadi string? Saya pikir poin OP pertanyaannya adalah bahwa ada saatnya Anda ingin benar-benar menggunakan nilai yang disimpan dalam a SecureString, yang berarti Anda harus mengeluarkannya dari sana, dan itu tidak lagi aman. Di semua Framework Class Library, sebenarnya tidak ada metode yang menerima SecureStringinput langsung sebagai (sejauh yang saya bisa lihat), jadi apa gunanya memegang nilai di dalam SecureStringdi tempat pertama?
stakx - tidak lagi berkontribusi
@ DamianLeszczyński-Vash, saya tahu bahwa SecureString tidak memiliki konstruktor string, tetapi poin saya adalah bahwa Anda juga (A) membuat SecureString dan menambahkan setiap char dari sebuah string ke dalamnya, atau (B) pada titik tertentu perlu menggunakan nilai yang disimpan dalam SecureString sebagai string untuk meneruskannya ke beberapa API. Yang sedang berkata, Anda membawa beberapa poin yang baik, dan saya bisa melihat bagaimana dalam beberapa kasus yang sangat spesifik itu bisa berguna.
Steven Jeffries
1
@stakx Anda akan mengirimnya melalui jaringan dengan mendapatkan char[]dan mengirimkan masing-masing charmelalui soket - tidak menciptakan objek yang dapat dikumpulkan sampah dalam proses.
user253751
Karakter [] dapat dikoleksi dan dapat diubah, sehingga dapat ditimpa.
Peter Ritchie
Tentu saja, juga mudah untuk lupa menimpa array itu. Apa pun itu, API apa pun yang Anda lewati juga dapat membuat salinan.
cao
10

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

... atau BSTR seperti yang Anda sebutkan, yang sepertinya tidak lebih aman

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).

Joe
sumber
1
+1, tetapi tidakkah Anda akan selalu berakhir "mengalahkan tujuannya"? Mengingat bahwa hampir tidak ada metode di Perpustakaan Kelas Kerangka menerima SecureStringinput sebagai, apa yang akan mereka gunakan? Anda harus selalu mengonversi kembali ke stringcepat atau lambat (atau BSTRseperti yang Anda sebutkan, yang sepertinya tidak lebih aman). Jadi mengapa harus repot-repot SecureString?
stakx - tidak lagi berkontribusi
5

Microsoft tidak merekomendasikan untuk menggunakan SecureStringkode yang lebih baru.

Dari dokumentasi Kelas SecureString :

Penting

Kami tidak menyarankan Anda menggunakan SecureStringkelas untuk pengembangan baru. Untuk informasi lebih lanjut, lihat SecureStringtidak boleh digunakan

Yang merekomendasikan:

Jangan gunakan SecureStringuntuk kode baru. Ketika 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. di GitHub.

SᴇM
sumber
4

Seperti yang telah Anda identifikasi dengan benar, SecureStringmenawarkan satu keunggulan spesifik atas string: penghapusan deterministik. Ada dua masalah dengan fakta ini:

  1. Seperti yang disebutkan orang lain dan seperti yang Anda perhatikan sendiri, ini tidak cukup dengan sendirinya. Anda harus memastikan bahwa setiap langkah proses (termasuk pengambilan input, konstruksi string, penggunaan, penghapusan, transportasi, dll) terjadi tanpa mengalahkan tujuan penggunaan SecureString. Ini berarti bahwa Anda harus berhati-hati untuk tidak pernah membuat GC-dikelola berubah stringatau 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 bekerja string, bukan SecureString. Dan bahkan jika Anda berhasil melakukan semuanya dengan benar ...
  2. SecureStringmelindungi terhadap jenis serangan yang sangat spesifik (dan bagi sebagian dari mereka, itu bahkan tidak dapat diandalkan). Misalnya, SecureStringtidak 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 SecureStringsemua kebutuhan Anda dan bahkan kemudian Anda harus tetap sadar bahwa ini aman hanya dalam keadaan tertentu.

Theodoros Chatzigiannakis
sumber
2
Anda berasumsi bahwa seorang penyerang dapat mengambil snapshot dari memori proses pada waktu tertentu. Itu belum tentu demikian. Pertimbangkan dump kecelakaan. Jika crash terjadi setelah aplikasi dilakukan dengan data sensitif, crash dump seharusnya tidak mengandung data sensitif.
4

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.

vikrantx
sumber
3

Saya ingin membahas hal ini:

Jika penyerang sudah memiliki sarana untuk inspeksi tumpukan, maka kemungkinan besar mereka (A) sudah memiliki sarana untuk membaca penekanan tombol, atau (B) secara fisik memiliki mesin ... Jadi akan menggunakan SecureStringmencegah mereka dari mendapatkan ke data lagian?

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 SecureStringsangat 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 tipe SecureString.

Athari
sumber
Hmm, pasti menarik untuk diketahui. Dalam semua kejujuran, saya sebenarnya tidak terlalu khawatir tentang jenis serangan yang diperlukan bahkan untuk mendapatkan Sistem. Menghilangkan nilai dari ingatan saya, saya hanya bertanya karena penasaran murni. Namun, terima kasih atas informasinya! :)
Steven Jeffries
2

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.

namespace Cardinity.Infrastructure
{
    using System.Security.Cryptography;
    using System;
    enum EncryptionMethods
    {
        None=0,
        HMACSHA1,
        HMACSHA256,
        HMACSHA384,
        HMACSHA512,
        HMACMD5
    }


internal class Protected
{
    private  Byte[] salt = Guid.NewGuid().ToByteArray();

    protected byte[] Protect(byte[] data)
    {
        try
        {
            return ProtectedData.Protect(data, salt, DataProtectionScope.CurrentUser);
        }
        catch (CryptographicException)//no reason for hackers to know it failed
        {
#if DEBUG
            throw;
#else
            return null;
#endif
        }
    }

    protected byte[] Unprotect(byte[] data)
    {
        try
        {
            return ProtectedData.Unprotect(data, salt, DataProtectionScope.CurrentUser);
        }
        catch (CryptographicException)//no reason for hackers to know it failed
        {
#if DEBUG
            throw;
#else
            return null;
#endif
        }
    }
}


    internal class SecretKeySpec:Protected,IDisposable
    {
        readonly EncryptionMethods _method;

        private byte[] _secretKey;
        public SecretKeySpec(byte[] secretKey, EncryptionMethods encryptionMethod)
        {
            _secretKey = Protect(secretKey);
            _method = encryptionMethod;
        }

        public EncryptionMethods Method => _method;
        public byte[] SecretKey => Unprotect( _secretKey);

        public void Dispose()
        {
            if (_secretKey == null)
                return;
            //overwrite array memory
            for (int i = 0; i < _secretKey.Length; i++)
            {
                _secretKey[i] = 0;
            }

            //set-null
            _secretKey = null;
        }
        ~SecretKeySpec()
        {
            Dispose();
        }
    }

    internal class Mac : Protected,IDisposable
    {
        byte[] rawHmac;
        HMAC mac;
        public Mac(SecretKeySpec key, string data)
        {

            switch (key.Method)
            {
                case EncryptionMethods.HMACMD5:
                    mac = new HMACMD5(key.SecretKey);
                    break;
                case EncryptionMethods.HMACSHA512:
                    mac = new HMACSHA512(key.SecretKey);
                    break;
                case EncryptionMethods.HMACSHA384:
                    mac = new HMACSHA384(key.SecretKey);
                    break;
                case EncryptionMethods.HMACSHA256:
                    mac = new HMACSHA256(key.SecretKey);

                break;
                case EncryptionMethods.HMACSHA1:
                    mac = new HMACSHA1(key.SecretKey);
                    break;

                default:                    
                    throw new NotSupportedException("not supported HMAC");
            }
            rawHmac = Protect( mac.ComputeHash(Cardinity.ENCODING.GetBytes(data)));            

        }

        public string AsBase64()
        {
            return System.Convert.ToBase64String(Unprotect(rawHmac));
        }

        public void Dispose()
        {
            if (rawHmac != null)
            {
                //overwrite memory address
                for (int i = 0; i < rawHmac.Length; i++)
                {
                    rawHmac[i] = 0;
                }

                //release memory now
                rawHmac = null;

            }
            mac?.Dispose();
            mac = null;

        }
        ~Mac()
        {
            Dispose();
        }
    }
}
Walter Vehoeven
sumber