String tidak berubah . Itu berarti setelah Anda membuat String
, jika proses lain dapat membuang memori, tidak ada cara (selain dari refleksi ) Anda dapat membuang data sebelum pengumpulan sampah dimulai.
Dengan sebuah array, Anda dapat menghapus data secara eksplisit setelah selesai. Anda dapat menimpa array dengan apa pun yang Anda suka, dan kata sandi tidak akan ada di mana pun dalam sistem, bahkan sebelum pengumpulan sampah.
Jadi ya, ini adalah masalah keamanan - tetapi bahkan menggunakan char[]
hanya mengurangi jendela peluang bagi penyerang, dan itu hanya untuk jenis serangan khusus ini.
Seperti disebutkan dalam komentar, ada kemungkinan bahwa array yang dipindahkan oleh pengumpul sampah akan meninggalkan salinan data yang tersesat dalam memori. Saya percaya ini khusus implementasi - pengumpul sampah dapat menghapus semua memori saat berjalan, untuk menghindari hal semacam ini. Bahkan jika itu terjadi, masih ada waktu di mana char[]
berisi karakter yang sebenarnya sebagai jendela serangan.
char[]
lokasi memotong garis serangan itu, sesuatu yang tidak mungkin saat digunakanString
.Sementara saran lain di sini tampaknya valid, ada satu alasan bagus lainnya. Dengan polos
String
Anda memiliki peluang lebih tinggi untuk secara tidak sengaja mencetak kata sandi ke log , monitor, atau tempat tidak aman lainnya.char[]
kurang rentan.Pertimbangkan ini:
Cetakan:
sumber
toString
isclassname@hashcode
.[C
mewakilichar[]
, sisanya adalah kode hash heksadesimal.Password
jenis kelas untuk ini. Ini kurang jelas, dan sulit untuk secara tidak sengaja melewati suatu tempat.Mengutip dokumen resmi, panduan Arsitektur Kriptografi Java mengatakan ini tentang kata sandi
char[]
vs.String
(tentang enkripsi berbasis kata sandi, tetapi ini lebih umum tentang kata sandi tentu saja):Panduan 2-2 dari Panduan Pengkodean Aman untuk Bahasa Pemrograman Java, Versi 4.0 juga mengatakan sesuatu yang serupa (meskipun aslinya dalam konteks logging):
sumber
String
ini cukup dipahami dengan baik dan bagaimana berperilaku di JVM ... ada alasan yang baik untuk menggunakanchar[]
di tempatString
ketika berhadapan dengan password dengan cara yang aman.At which point
- itu adalah spesifik aplikasi, tetapi aturan umum adalah melakukannya segera setelah Anda mendapatkan sesuatu yang seharusnya menjadi kata sandi (plaintext atau sebaliknya). Anda mendapatkannya dari browser sebagai bagian dari permintaan HTTP, misalnya. Anda tidak dapat mengontrol pengiriman, tetapi Anda dapat mengontrol penyimpanan Anda sendiri, jadi segera setelah Anda mendapatkannya, masukkan ke dalam char [], lakukan apa yang perlu Anda lakukan dengannya, kemudian atur semua ke '0' dan biarkan gc ambil kembali.Array karakter (
char[]
) dapat dihapus setelah digunakan dengan mengatur setiap karakter ke nol dan Strings tidak. Jika seseorang entah bagaimana dapat melihat gambar memori, mereka dapat melihat kata sandi dalam teks biasa jika Strings digunakan, tetapi jikachar[]
digunakan, setelah membersihkan data dengan 0, kata sandi aman.sumber
HttpServletRequest
objek dalam plaintext. Jika versi JVM 1.6 atau lebih rendah, itu akan berada di ruang permgen. Jika dalam 1,7, itu masih dapat dibaca sampai dikumpulkan. (Kapan pun itu.)intern()
string sembarangan. Tetapi Anda benar bahwaString
instans ada di tempat pertama (sampai dikumpulkan) dan mengubahnya menjadichar[]
array setelah itu tidak mengubahnya.new String()
atauStringBuilder.toString()
saya mengelola aplikasi dengan banyak konstanta string, dan kami memiliki banyak permgen creep sebagai hasilnya. Sampai 1.7.intern()
string sewenang-wenang dapat menyebabkan alokasi string yang setara di ruang permgen. Yang terakhir bisa mendapatkan GC'ed, jika tidak ada string literal dari konten yang sama berbagi objek itu ...Beberapa orang percaya bahwa Anda harus menimpa memori yang digunakan untuk menyimpan kata sandi setelah Anda tidak lagi membutuhkannya. Ini mengurangi waktu jendela seorang penyerang harus membaca kata sandi dari sistem Anda dan sepenuhnya mengabaikan fakta bahwa penyerang sudah membutuhkan akses yang cukup untuk membajak memori JVM untuk melakukan ini. Seorang penyerang dengan akses sebanyak itu dapat menangkap peristiwa utama Anda yang membuat ini sama sekali tidak berguna (AFAIK, jadi tolong perbaiki saya jika saya salah).
Memperbarui
Berkat komentar saya harus memperbarui jawaban saya. Rupanya ada dua kasus di mana ini dapat menambahkan (sangat) peningkatan keamanan kecil karena mengurangi waktu kata sandi bisa mendarat di hard drive. Masih saya pikir itu berlebihan untuk kebanyakan kasus penggunaan.
Jika memungkinkan, menonaktifkan dump inti dan file swap akan menangani kedua masalah. Namun, mereka akan memerlukan hak administrator dan dapat mengurangi fungsionalitas (lebih sedikit memori untuk digunakan) dan menarik RAM dari sistem yang sedang berjalan masih akan menjadi masalah yang valid.
sumber
Saya tidak berpikir ini adalah saran yang valid, tapi, setidaknya saya bisa menebak alasannya.
Saya pikir motivasi ingin memastikan bahwa Anda dapat menghapus semua jejak kata sandi di memori segera dan dengan pasti setelah digunakan. Dengan
char[]
Anda dapat menimpa setiap elemen array dengan kosong atau sesuatu pasti. Anda tidak dapat mengedit nilai internal denganString
cara itu.Tapi itu saja bukan jawaban yang bagus; mengapa tidak memastikan referensi ke
char[]
atauString
tidak melarikan diri? Maka tidak ada masalah keamanan. Tetapi masalahnya adalah bahwaString
objek dapatintern()
diedit secara teori dan tetap hidup di dalam kolam konstan. Saya kira menggunakanchar[]
melarang kemungkinan ini.sumber
char[]
dapat dimodifikasi, dan kemudian itu tidak relevan apakah itu dikumpulkan atau tidak. Dan karena string magang perlu dilakukan secara eksplisit untuk non-literal, itu sama seperti mengatakan bahwa achar[]
dapat dirujuk oleh bidang statis.Jawabannya sudah diberikan, tetapi saya ingin berbagi masalah yang saya temukan belakangan ini dengan perpustakaan standar Java. Sementara mereka sangat berhati-hati saat mengganti string kata sandi dengan di
char[]
mana - mana (yang tentu saja merupakan hal yang baik), data keamanan-kritis lainnya tampaknya diabaikan ketika datang untuk membersihkannya dari memori.Saya sedang memikirkan misalnya kelas PrivateKey . Pertimbangkan skenario di mana Anda akan memuat kunci RSA pribadi dari file PKCS # 12, menggunakannya untuk melakukan beberapa operasi. Sekarang dalam kasus ini, mengendus kata sandi saja tidak akan banyak membantu Anda selama akses fisik ke file kunci dibatasi dengan benar. Sebagai seorang penyerang, Anda akan jauh lebih baik jika Anda mendapatkan kunci secara langsung daripada kata sandi. Informasi yang diinginkan dapat bocor berlipat ganda, core dumps, sesi debugger atau swap file hanyalah beberapa contoh.
Dan ternyata, tidak ada yang memungkinkan Anda menghapus informasi pribadi dari
PrivateKey
dari memori, karena tidak ada API yang memungkinkan Anda menghapus byte yang membentuk informasi yang sesuai.Ini adalah situasi yang buruk, karena makalah ini menjelaskan bagaimana keadaan ini dapat berpotensi dieksploitasi.
Pustaka OpenSSL misalnya menimpa bagian memori kritis sebelum kunci pribadi dibebaskan. Karena Java dikumpulkan dari sampah, kita perlu metode eksplisit untuk menghapus dan membatalkan informasi pribadi untuk kunci Java, yang akan diterapkan segera setelah menggunakan kunci tersebut.
sumber
PrivateKey
yang tidak benar-benar memuat konten privatnya ke dalam memori: misalnya melalui token perangkat keras PKCS # 11. Mungkin implementasi perangkat lunak PKCS # 11 dapat menangani pembersihan memori secara manual. Mungkin menggunakan sesuatu seperti toko NSS (yang berbagi sebagian besar implementasinya denganPKCS11
jenis toko di Jawa) lebih baik. TheKeychainStore
(OSX keystore) beban isi penuh dari kunci pribadi ke dalam nyaPrivateKey
kasus, tetapi seharusnya tidak perlu. (Tidak yakin apa yang dilakukanWINDOWS-MY
KeyStore di Windows.)Seperti yang dinyatakan Jon Skeet, tidak ada jalan lain kecuali menggunakan refleksi.
Namun, jika refleksi adalah pilihan bagi Anda, Anda dapat melakukan ini.
saat dijalankan
Catatan: jika karakter String [] telah disalin sebagai bagian dari siklus GC, ada kemungkinan salinan sebelumnya ada di suatu tempat di memori.
Salinan lama ini tidak akan muncul di heap dump, tetapi jika Anda memiliki akses langsung ke memori mentah proses, Anda bisa melihatnya. Secara umum Anda harus menghindari siapa pun yang memiliki akses seperti itu.
sumber
'***********'
.Scanner
buffer internal dan, karena Anda tidak menggunakannyaSystem.console().readPassword()
, dalam bentuk yang dapat dibaca di jendela konsol. Tetapi untuk sebagian besar kasus penggunaan praktis, durasiusePassword
eksekusi adalah masalah yang sebenarnya. Misalnya, ketika membuat koneksi ke komputer lain, dibutuhkan waktu yang signifikan dan memberi tahu penyerang bahwa ini adalah waktu yang tepat untuk mencari kata sandi di heap. Satu-satunya solusi adalah mencegah penyerang membaca memori heap ...Ini semua alasannya, kita harus memilih array char [] daripada String untuk kata sandi.
1. Karena String tidak dapat diubah di Jawa, jika Anda menyimpan kata sandi sebagai teks biasa, kata itu akan tersedia dalam memori sampai pengumpul Sampah mengosongkannya, dan karena String digunakan dalam kumpulan String untuk penggunaan kembali, ada kemungkinan yang cukup tinggi bahwa itu akan tetap tersimpan dalam memori untuk waktu yang lama, yang menimbulkan ancaman keamanan.
Karena siapa pun yang memiliki akses ke dump memori dapat menemukan kata sandi dalam teks yang jelas, itu alasan lain Anda harus selalu menggunakan kata sandi terenkripsi daripada teks biasa. Karena String tidak dapat diubah, tidak mungkin konten String dapat diubah karena perubahan apa pun akan menghasilkan String baru, sementara jika Anda menggunakan karakter [] Anda masih dapat mengatur semua elemen sebagai kosong atau nol. Jadi menyimpan kata sandi dalam susunan karakter jelas mengurangi risiko keamanan mencuri kata sandi.
2. Java sendiri merekomendasikan menggunakan metode getPassword () dari JPasswordField yang mengembalikan karakter [], alih-alih metode getText () yang sudah usang yang mengembalikan kata sandi dalam teks yang jelas yang menyatakan alasan keamanan. Adalah baik untuk mengikuti saran dari tim Java dan mematuhi standar daripada menentangnya.
3. Dengan String selalu ada risiko mencetak teks biasa dalam file log atau konsol tetapi jika Anda menggunakan Array Anda tidak akan mencetak konten array, tetapi sebaliknya lokasi memorinya akan dicetak. Meski bukan alasan sebenarnya, itu tetap masuk akal.
Dirujuk dari blog ini . Saya harap ini membantu.
sumber
Sunting: Kembali ke jawaban ini setelah satu tahun penelitian keamanan, saya menyadari itu membuat implikasi yang agak disayangkan bahwa Anda akan benar-benar membandingkan kata sandi plaintext. Tolong jangan. Gunakan hash satu arah yang aman dengan garam dan sejumlah iterasi yang masuk akal . Pertimbangkan untuk menggunakan perpustakaan: hal-hal ini sulit untuk diperbaiki!
Jawaban asli: Bagaimana dengan fakta bahwa String.equals () menggunakan evaluasi hubung singkat , dan karenanya rentan terhadap serangan waktu? Ini mungkin tidak mungkin, tetapi Anda secara teoritis dapat mengatur waktu perbandingan kata sandi untuk menentukan urutan karakter yang benar.
Beberapa lebih banyak sumber daya tentang serangan waktu:
sumber
Arrays.equals
untukchar[]
setinggi untukString.equals
. Jika ada yang peduli, ada kelas kunci khusus yang mengenkapsulasi kata sandi yang sebenarnya dan mengurus masalah - oh, tunggu, paket keamanan sebenarnya telah mendedikasikan kelas-kelas utama, T&J ini hanya tentang kebiasaan di luar mereka, katakanlah, misalnyaJPasswordField
, untuk menggunakanchar[]
alih-alihString
(di mana algoritma sebenarnya digunakanbyte[]
pula).sleep(secureRandom.nextInt())
sebelum menolak upaya login, itu tidak hanya menghilangkan kemungkinan serangan waktu, tetapi juga membuat upaya penangkal kekuatan brutal.Tidak ada yang array char memberi Anda vs String kecuali Anda membersihkannya secara manual setelah digunakan, dan saya belum melihat ada yang benar-benar melakukan itu. Jadi bagi saya preferensi char [] vs String agak berlebihan.
Lihatlah pustaka Spring Security yang banyak digunakan di sini dan tanyakan pada diri Anda - apakah password Spring Security tidak kompeten atau char [] tidak masuk akal. Ketika beberapa peretas jahat mengambil memori dump RAM Anda pastikan ia akan mendapatkan semua kata sandi bahkan jika Anda menggunakan cara canggih untuk menyembunyikannya.
Namun, Java berubah setiap saat, dan beberapa fitur menakutkan seperti Deduplikasi String Java 8 mungkin menginternir objek String tanpa sepengetahuan Anda. Tapi itu percakapan yang berbeda.
sumber
String tidak berubah dan tidak dapat diubah setelah mereka dibuat. Membuat kata sandi sebagai string akan meninggalkan referensi menyimpang ke kata sandi pada heap atau pada kumpulan String. Sekarang jika seseorang mengambil tumpukan proses Java dan dengan hati-hati memindai dia mungkin bisa menebak kata sandi. Tentu saja string ini tidak digunakan akan menjadi sampah yang dikumpulkan tetapi itu tergantung pada kapan GC masuk.
Di sisi lain, char [] dapat berubah begitu otentikasi selesai, Anda dapat menimpa mereka dengan karakter seperti semua M atau backslash. Sekarang bahkan jika seseorang mengambil heap dump, dia mungkin tidak bisa mendapatkan kata sandi yang saat ini tidak digunakan. Ini memberi Anda lebih banyak kontrol dalam arti seperti membersihkan konten Objek sendiri vs menunggu GC melakukannya.
sumber
strings
DANString
kumpulan (kumpulan string yang sebelumnya digunakan) KEDUA disimpan di Permgen sebelum 1,7. Juga, Lihat bagian 5.1: docs.oracle.com/javase/specs/jvms/se6/html/... JVM selalu memeriksaStrings
untuk melihat apakah mereka memiliki nilai referensi yang sama, dan akan memanggilString.intern()
UNTUK ANDA. Hasilnya adalah bahwa setiap kali JVM mendeteksi String yang identik di dalamconstant_pool
atau menumpuknya akan memindahkan mereka ke permgen. Dan saya mengerjakan beberapa aplikasi dengan "creeping permgen" hingga 1,7. Itu masalah nyata.constant_pool
yang terletak di permgen, dan kemudian jika string digunakan lebih dari sekali, itu akan diinternir.String tidak dapat diubah dan pergi ke kumpulan string. Setelah ditulis, tidak dapat ditimpa.
char[]
adalah array yang harus Anda timpa setelah menggunakan kata sandi dan inilah yang harus dilakukan:Satu skenario di mana penyerang bisa menggunakannya adalah crashdump - ketika JVM crash dan menghasilkan dump memori - Anda akan dapat melihat kata sandi.
Itu belum tentu penyerang eksternal jahat. Ini bisa menjadi pengguna dukungan yang memiliki akses ke server untuk keperluan pemantauan. Dia bisa mengintip crashdump dan menemukan kata sandinya.
sumber
request.getPassword()
membuat string dan menambahkannya ke kolam?ch = '0'
mengubah variabel lokalch
; itu tidak berpengaruh pada array. Dan contoh Anda tidak ada gunanya, Anda mulai dengan instance string yang Anda panggiltoCharArray()
, membuat array baru dan bahkan ketika Anda menimpa array baru dengan benar, itu tidak mengubah instance string, sehingga tidak memiliki keuntungan dibandingkan hanya menggunakan string contoh.Arrays.fill(pass, '0');
Jawaban singkat dan langsung adalah karena
char[]
bisa berubah sementaraString
objek tidak.Strings
di Jawa adalah objek abadi. Itulah sebabnya mereka tidak dapat dimodifikasi setelah dibuat, dan oleh karena itu satu-satunya cara agar isinya dihapus dari memori adalah dengan mengumpulkannya. Itu hanya akan terjadi ketika memori yang dibebaskan oleh objek dapat ditimpa, dan data akan hilang.Sekarang pengumpulan sampah di Jawa tidak terjadi pada interval yang dijamin. Itu
String
demikian dapat bertahan dalam memori untuk waktu yang lama, dan jika suatu proses crash selama waktu ini, isi string mungkin berakhir di tempat penyimpanan memori atau log.Dengan susunan karakter , Anda dapat membaca kata sandi, menyelesaikannya sesegera mungkin, dan kemudian segera mengubah isinya.
sumber
String dalam java tidak dapat diubah. Jadi, setiap kali string dibuat, itu akan tetap dalam memori sampai sampah dikumpulkan. Jadi siapa pun yang memiliki akses ke memori dapat membaca nilai string.
Jika nilai string diubah maka akhirnya akan membuat string baru. Jadi nilai asli dan nilai yang dimodifikasi tetap berada di memori sampai sampah dikumpulkan.
Dengan array karakter, isi array dapat dimodifikasi atau dihapus setelah tujuan kata sandi disajikan. Isi asli array tidak akan ditemukan dalam memori setelah dimodifikasi dan bahkan sebelum pengumpulan sampah dimulai.
Karena masalah keamanan, lebih baik menyimpan kata sandi sebagai array karakter.
sumber
Dapat diperdebatkan apakah Anda harus menggunakan String atau menggunakan Char [] untuk tujuan ini karena keduanya memiliki kelebihan dan kekurangan. Itu tergantung pada apa yang dibutuhkan pengguna.
Karena String di Java tidak dapat diubah, setiap kali beberapa orang mencoba untuk memanipulasi string Anda, itu menciptakan Obyek baru dan String yang ada tetap tidak terpengaruh. Ini bisa dilihat sebagai keuntungan untuk menyimpan kata sandi sebagai String, tetapi objek tetap ada dalam memori bahkan setelah digunakan. Jadi, jika ada orang yang entah bagaimana mendapatkan lokasi memori objek, orang itu dapat dengan mudah melacak kata sandi Anda yang tersimpan di lokasi itu.
Karakter [] bisa berubah, tetapi ia memiliki keuntungan bahwa setelah penggunaannya, pemrogram dapat secara eksplisit membersihkan array atau mengabaikan nilai. Jadi ketika sudah selesai digunakan itu sudah dibersihkan dan tidak ada yang bisa tahu tentang informasi yang Anda simpan.
Berdasarkan keadaan di atas, orang bisa mendapatkan ide apakah akan pergi dengan String atau pergi dengan Char [] untuk persyaratan mereka.
sumber
Tali Kasus:
Kasus CHAR ARRAY:
sumber