Saya membuat aplikasi yang akan menyimpan kata sandi, yang dapat diambil dan dilihat pengguna. Kata sandi untuk perangkat perangkat keras, jadi memeriksa hash tidak perlu dilakukan.
Yang perlu saya ketahui adalah:
Bagaimana cara mengenkripsi dan mendekripsi kata sandi dalam PHP?
Algoritma apa yang paling aman untuk mengenkripsi kata sandi?
Di mana saya menyimpan kunci pribadi?
Alih-alih menyimpan kunci privat, apakah lebih baik meminta pengguna memasukkan kunci privat kapan saja mereka membutuhkan kata sandi yang didekripsi? (Pengguna aplikasi ini dapat dipercaya)
Dengan cara apa kata sandi dapat dicuri dan didekripsi? Apa yang perlu saya waspadai?
php
security
encryption
passwords
HyderA
sumber
sumber
Jawaban:
Secara pribadi, saya akan menggunakan
mcrypt
seperti orang lain yang diposting. Tetapi ada banyak lagi yang perlu diperhatikan ...Bagaimana cara mengenkripsi dan mendekripsi kata sandi dalam PHP?
Lihat di bawah ini untuk kelas yang kuat yang mengurus semuanya untuk Anda:
Algoritma apa yang paling aman untuk mengenkripsi kata sandi?
paling aman ? siapapun dari mereka. Metode teraman jika Anda akan mengenkripsi adalah untuk melindungi terhadap kerentanan pengungkapan informasi (XSS, inklusi jarak jauh, dll). Jika keluar, penyerang akhirnya dapat memecahkan enkripsi (tidak ada enkripsi yang 100% tidak dapat dibalik tanpa kunci - seperti yang ditunjukkan oleh @NullUserException, hal ini tidak sepenuhnya benar. Ada beberapa skema enkripsi yang tidak mungkin diretas seperti OneTimePad ) .
Di mana saya menyimpan kunci pribadi?
Apa yang akan saya lakukan adalah menggunakan 3 kunci. Satu adalah pengguna yang disediakan, satu adalah aplikasi spesifik dan yang lainnya adalah pengguna spesifik (seperti garam). Kunci spesifik aplikasi dapat disimpan di mana saja (dalam file konfigurasi di luar web-root, dalam variabel lingkungan, dll). Yang khusus pengguna akan disimpan dalam kolom di db di sebelah kata sandi terenkripsi. Pengguna yang disediakan tidak akan disimpan. Kemudian, Anda akan melakukan sesuatu seperti ini:
Manfaat di sana, adalah bahwa 2 kunci dapat dikompromikan tanpa data dikompromikan. Jika ada serangan SQL Injection, mereka bisa mendapatkan
$userKey
, tetapi bukan yang lain 2. Jika ada exploit server lokal, mereka bisa mendapatkan$userKey
dan$serverKey
, tetapi bukan yang ketiga$userSuppliedKey
. Jika mereka mengalahkan pengguna dengan kunci pas, mereka bisa mendapatkan$userSuppliedKey
, tetapi tidak 2 yang lain (tapi sekali lagi, jika pengguna dipukul dengan kunci pas, Anda toh sudah terlambat).Alih-alih menyimpan kunci privat, apakah lebih baik meminta pengguna memasukkan kunci privat kapan saja mereka membutuhkan kata sandi yang didekripsi? (Pengguna aplikasi ini dapat dipercaya)
Benar. Sebenarnya, itulah satu-satunya cara saya melakukannya. Kalau tidak, Anda perlu menyimpan versi yang tidak dienkripsi dalam format penyimpanan yang tahan lama (memori bersama seperti APC atau memcached, atau dalam file sesi). Itu membuat Anda terkena kompromi tambahan. Jangan pernah menyimpan versi kata sandi yang tidak terenkripsi dalam apa pun kecuali variabel lokal.
Dengan cara apa kata sandi dapat dicuri dan didekripsi? Apa yang perlu saya waspadai?
Segala bentuk kompromi dari sistem Anda akan membuat mereka melihat data terenkripsi. Jika mereka dapat menyuntikkan kode atau membuka sistem file Anda, mereka dapat melihat data yang didekripsi (karena mereka dapat mengedit file yang mendekripsi data). Segala bentuk Replay atau serangan MITM juga akan memberi mereka akses penuh ke kunci yang terlibat. Mengendus lalu lintas HTTP mentah juga akan memberi mereka kunci.
Gunakan SSL untuk semua lalu lintas. Dan pastikan tidak ada di server yang memiliki kerentanan (CSRF, XSS, SQL Injection, Privilege Escalation, Eksekusi Kode Jarak Jauh, dll).
Sunting: Ini adalah implementasi kelas PHP dari metode enkripsi yang kuat:
Perhatikan bahwa saya menggunakan fungsi ditambahkan dalam PHP 5.6:
hash_equals
. Jika Anda berada di bawah 5.6, Anda dapat menggunakan fungsi pengganti ini yang mengimplementasikan fungsi perbandingan aman-waktu menggunakan verifikasi HMAC ganda :Pemakaian:
Lalu, untuk mendekripsi:
Perhatikan bahwa saya menggunakan
$e2
kedua kalinya untuk menunjukkan kepada Anda berbagai contoh masih akan mendekripsi data dengan benar.Sekarang, bagaimana cara kerjanya / mengapa menggunakannya di atas solusi lain:
Kunci
Kunci tidak digunakan secara langsung. Sebagai gantinya, kunci diregangkan oleh derivasi PBKDF2 standar.
Kunci yang digunakan untuk enkripsi adalah unik untuk setiap blok teks terenkripsi. Karenanya, kunci yang disediakan menjadi "kunci utama". Karenanya kelas ini menyediakan rotasi kunci untuk kunci sandi dan kunci autentik.
CATATAN PENTING ,
$rounds
parameter ini dikonfigurasikan untuk kunci acak sejati dengan kekuatan yang cukup (minimum 128 bit Cryptographically Secure random). Jika Anda akan menggunakan kata sandi, atau kunci non-acak (atau kurang acak dari 128 bit CS acak), Anda harus meningkatkan parameter ini. Saya menyarankan minimal 10.000 untuk kata sandi (semakin banyak yang Anda mampu, semakin baik, tetapi akan menambah runtime) ...Integritas data
Enkripsi:
MCRYPT_BLOWFISH
atauMCRYPT_RIJNDAEL_128
sandi danMCRYPT_MODE_CBC
untuk mode. Itu cukup kuat, dan masih cukup cepat (siklus enkripsi dan dekripsi memakan waktu sekitar 1/2 detik pada mesin saya).Sekarang, ke poin 3 dari daftar pertama, apa yang akan memberi Anda adalah fungsi seperti ini:
Anda dapat merentangkannya dalam
makeKey()
fungsi, tetapi karena itu akan diregangkan nanti, tidak ada poin besar untuk melakukannya.Sejauh ukuran penyimpanan, itu tergantung pada teks biasa. Blowfish menggunakan ukuran blok 8 byte, sehingga Anda akan memiliki:
Jadi untuk sumber data 16 karakter, akan ada 16 karakter data yang akan dienkripsi. Jadi itu berarti ukuran data terenkripsi yang sebenarnya adalah 16 byte karena padding. Kemudian tambahkan 16 byte untuk garam dan 64 byte untuk hmac dan ukuran total yang disimpan adalah 96 byte. Jadi paling tidak ada 80 karakter overhead, dan paling buruk 87 karakter overhead ...
Saya harap itu membantu...
Catatan: 12/11/12: Saya baru saja memperbarui kelas ini dengan metode enkripsi JAUH lebih baik, menggunakan kunci turunan yang lebih baik, dan memperbaiki generasi MAC ...
sumber
-64
s untuk-128
membantu (sehingga Anda mendapatkan$enc = substr($data, 128, -128)
dan$mac = substr($data, -128);
Bagaimana cara mengenkripsi dan mendekripsi kata sandi dalam PHP? Dengan menerapkan salah satu dari banyak algoritma enkripsi. (atau menggunakan salah satu dari banyak perpustakaan)
Algoritma apa yang paling aman untuk mengenkripsi kata sandi? Ada banyak algoritma yang berbeda, tidak ada yang 100% aman. Tetapi banyak dari mereka cukup aman untuk tujuan perdagangan dan bahkan militer
Di mana saya menyimpan kunci pribadi? Jika Anda telah memutuskan untuk mengimplementasikan kunci publik - algoritma kriptografi (misalnya RSA), Anda tidak menyimpan kunci pribadi. pengguna memiliki kunci pribadi. sistem Anda memiliki kunci publik yang dapat disimpan di mana saja Anda inginkan.
Alih-alih menyimpan kunci privat, apakah lebih baik meminta pengguna memasukkan kunci privat kapan saja mereka membutuhkan kata sandi yang didekripsi? (Pengguna aplikasi ini dapat dipercaya) Nah, jika pengguna Anda dapat mengingat bilangan prima yang sangat panjang maka - ya, mengapa tidak. Tetapi umumnya Anda harus membuat sistem yang akan memungkinkan pengguna untuk menyimpan kunci mereka di suatu tempat.
Dengan cara apa kata sandi dapat dicuri dan didekripsi? Apa yang perlu saya waspadai? Ini tergantung pada algoritma yang digunakan. Namun selalu pastikan bahwa Anda tidak mengirim kata sandi yang tidak dienkripsi ke atau dari pengguna. Enkripsi / dekripsi di sisi klien, atau gunakan https (atau pengguna alat kriptografi lainnya untuk mengamankan koneksi antara server dan klien).
Namun jika yang Anda butuhkan adalah menyimpan kata sandi dengan cara terenkripsi, saya sarankan Anda menggunakan XOR Cipher yang sederhana. Masalah utama dengan algoritma ini adalah bahwa ia dapat dengan mudah dipatahkan oleh analisis frekuensi. Namun karena umumnya kata sandi tidak dibuat dari paragraf panjang teks bahasa Inggris, saya rasa Anda tidak perlu khawatir. Masalah kedua dengan XOR Cipher adalah bahwa jika Anda memiliki pesan dalam bentuk terenkripsi dan dekripsi, Anda dapat dengan mudah menemukan kata sandi yang dienkripsi. Sekali lagi, bukan masalah besar dalam kasus Anda karena hanya mempengaruhi pengguna yang sudah dikompromikan dengan cara lain.
sumber
Contoh dari manual sedikit diedit untuk contoh ini):
Anda akan menggunakan mcrypt_decrypt untuk mendekripsi kata sandi Anda.
Algoritma terbaik agak subyektif - tanyakan 5 orang, dapatkan 5 jawaban. Secara pribadi jika default (Blowfish) tidak cukup baik untuk Anda, Anda mungkin memiliki masalah lebih besar!
Mengingat bahwa diperlukan oleh PHP untuk mengenkripsi - tidak yakin Anda dapat menyembunyikannya di mana saja - selamat datang komentar tentang ini. Praktik pengkodean PHP standar terbaik tentu saja berlaku!
Mengingat bahwa kunci enkripsi akan tetap ada dalam kode Anda, tidak yakin apa yang akan Anda peroleh, asalkan sisa aplikasi Anda aman.
Jelas, jika kata sandi terenkripsi dan kunci enkripsi dicuri, maka game over.
Saya akan menempatkan pengendara pada jawaban saya - saya bukan ahli PHP crypto, tapi, saya pikir apa yang saya jawab adalah praktik standar - saya menyambut komentar yang mungkin dimiliki orang lain.
sumber
$pass = $text
. Saya pikir dia mengubahnya untuk memenuhi pertanyaan, dan tidak melihat kejadian kedua.MCRYPT_MODE_ECB
tidak menggunakan infus. Kedua, jika itu terjadi, Anda harus menyimpan IV karena Anda tidak dapat mendekripsi data tanpa itu ...Banyak pengguna menyarankan menggunakan mcrypt ... yang benar, tetapi saya ingin melangkah lebih jauh untuk membuatnya lebih mudah disimpan dan ditransfer (karena kadang-kadang nilai yang dienkripsi dapat membuat mereka sulit dikirim menggunakan teknologi lain seperti curl, atau json) .
Setelah Anda berhasil dienkripsi menggunakan mcrypt, jalankan melalui base64_encode dan kemudian konversikan ke kode hex. Sekali dalam kode hex mudah untuk mentransfer dalam berbagai cara.
Dan di sisi lain:
sumber
Saya hanya menyarankan enkripsi kunci publik jika Anda ingin kemampuan untuk mengatur kata sandi pengguna tanpa interaksi mereka (ini dapat berguna untuk mengatur ulang dan kata sandi bersama).
Kunci publik
openssl_public_encrypt
danopenssl_private_decrypt
Simetris
Kedua
4
. Ya - pengguna harus memasukkan kata sandi aplikasi mereka setiap saat, tetapi menyimpannya di sesi akan menimbulkan masalah lain5
.sumber
openssl_private_decrypt()
.Saya mencoba sesuatu seperti ini tetapi harap dicatat bahwa saya bukan cryptographer atau saya memiliki pengetahuan mendalam tentang
php
atau bahasa pemrograman apa pun. Itu hanya sebuah ide. Gagasan saya adalah menyimpankey
dalam beberapa file ataudatabase
(atau memasukkan secara manual) yang (lokasi) tidak dapat diprediksi dengan mudah (Dan tentu saja apa pun akan didekripsi suatu hari nanti, konsepnya adalah untuk memperpanjang waktu dekripsi) dan mengenkripsi informasi sensitif.Harap dicatat bahwa ini hanyalah sebuah konsep. Setiap perbaikan pada kode ini akan sangat dihargai.
sumber
Eh? Saya tidak mengerti. Apakah maksud Anda kata sandi itu harus dapat dipulihkan?
Seperti yang orang lain katakan, ekstensi mcrypt menyediakan akses ke banyak fungsi kriptografi - namun Anda mengundang pengguna untuk meletakkan semua telur mereka dalam satu keranjang - yang akan berpotensi menjadi sasaran penyerang - dan jika Anda bahkan tidak tahu bagaimana memulai memecahkan masalah maka Anda melakukan merugikan pengguna. Anda tidak dalam posisi untuk memahami bagaimana melindungi data.
Sebagian besar kerentanan keamanan muncul bukan karena algoritma yang mendasarinya cacat atau tidak aman - tetapi karena masalah dengan cara algoritma digunakan dalam kode aplikasi.
Karena itu, adalah mungkin untuk membangun sistem yang cukup aman.
Anda hanya harus mempertimbangkan enkripsi asimetris jika Anda memiliki persyaratan bagi pengguna untuk membuat pesan aman yang dapat dibaca oleh pengguna (spesifik) lainnya. Alasannya karena harganya yang mahal. Jika Anda hanya ingin memberikan repositori bagi pengguna untuk memasukkan dan mengambil data mereka sendiri, enkripsi simetris memadai.
Namun, jika Anda menyimpan kunci untuk mendekripsi pesan di tempat yang sama dengan pesan terenkripsi (atau di mana pesan terenkripsi disimpan) maka sistem tidak aman. Gunakan token yang sama untuk mengautentikasi pengguna seperti untuk kunci dekripsi (atau dalam hal enkripsi asimetris, gunakan token sebagai frasa kunci pribadi). Karena Anda harus menyimpan token di server tempat dekripsi berlangsung setidaknya untuk sementara, Anda mungkin ingin mempertimbangkan untuk menggunakan substrat penyimpanan sesi yang tidak dapat dicari, atau meneruskan token langsung ke daemon yang terkait dengan sesi yang akan menyimpan token dalam memori dan melakukan dekripsi pesan sesuai permintaan.
sumber
Gunakan password_hash dan password_verify
Dan untuk mendekripsi:
sumber