OK, saya jelaskan: jika Anda memasukkan data pengguna, atau apapun yang berasal dari data pengguna ke dalam cookie untuk tujuan ini, Anda melakukan sesuatu yang salah.
Sana. Saya mengatakannya. Sekarang kita bisa beralih ke jawaban yang sebenarnya.
Apa yang salah dengan hashing data pengguna, Anda bertanya? Yah, itu turun ke permukaan paparan dan keamanan melalui ketidakjelasan.
Bayangkan sesaat bahwa Anda seorang penyerang. Anda melihat cookie kriptografi yang diset untuk mengingat-saya di sesi Anda. Lebar 32 karakter. Wah. Itu mungkin MD5 ...
Mari kita bayangkan juga bahwa mereka mengetahui algoritma yang Anda gunakan. Sebagai contoh:
md5(salt+username+ip+salt)
Sekarang, yang perlu dilakukan penyerang hanyalah memaksa "garam" (yang sebenarnya bukan garam, tetapi lebih dari itu nanti), dan dia sekarang dapat menghasilkan semua token palsu yang dia inginkan dengan nama pengguna apa pun untuk alamat IP-nya! Tapi memaksakan diri dengan garam itu sulit, bukan? Benar. Tetapi GPU modern sangat bagus dalam hal itu. Dan kecuali Anda menggunakan keacakan yang cukup di dalamnya (membuatnya cukup besar), itu akan jatuh dengan cepat, dan dengan itu kunci ke istananya.
Singkatnya, satu-satunya hal yang melindungi Anda adalah garam, yang tidak benar-benar melindungi Anda seperti yang Anda pikirkan.
Tapi tunggu!
Semua itu diprediksikan bahwa penyerang tahu algoritma! Jika ini rahasia dan membingungkan, maka Anda aman, bukan? SALAH . Garis pemikiran itu memiliki nama: Keamanan Melalui Ketidakjelasan , yang TIDAK PERNAH bisa diandalkan.
Cara yang Lebih Baik
Cara yang lebih baik adalah tidak pernah membiarkan informasi pengguna meninggalkan server, kecuali untuk id.
Saat pengguna masuk, buat token acak besar (128 hingga 256 bit). Tambahkan itu ke tabel database yang memetakan token ke userid, dan kemudian kirimkan ke klien dalam cookie.
Bagaimana jika penyerang menebak token acak dari pengguna lain?
Baiklah, mari kita berhitung di sini. Kami membuat token acak 128 bit. Itu artinya ada:
possibilities = 2^128
possibilities = 3.4 * 10^38
Sekarang, untuk menunjukkan seberapa besar angka itu, mari bayangkan setiap server di internet (katakanlah 50.000.000 hari ini) mencoba untuk memaksa jumlah itu dengan kecepatan masing-masing 1.000.000.000 per detik. Pada kenyataannya server Anda akan meleleh di bawah beban seperti itu, tetapi mari kita lakukan ini.
guesses_per_second = servers * guesses
guesses_per_second = 50,000,000 * 1,000,000,000
guesses_per_second = 50,000,000,000,000,000
Jadi 50 kuadriliun tebakan per detik. Itu cepat! Baik?
time_to_guess = possibilities / guesses_per_second
time_to_guess = 3.4e38 / 50,000,000,000,000,000
time_to_guess = 6,800,000,000,000,000,000,000
Jadi 6,8 sextillion detik ...
Mari kita coba bawa ke nomor yang lebih ramah.
215,626,585,489,599 years
Atau lebih baik lagi:
47917 times the age of the universe
Ya, itu 47917 kali usia alam semesta ...
Pada dasarnya, itu tidak akan retak.
Jadi ringkasnya:
Pendekatan yang lebih baik yang saya sarankan adalah menyimpan cookie dengan tiga bagian.
function onLogin($user) {
$token = GenerateRandomToken(); // generate a token, should be 128 - 256 bit
storeTokenForUser($user, $token);
$cookie = $user . ':' . $token;
$mac = hash_hmac('sha256', $cookie, SECRET_KEY);
$cookie .= ':' . $mac;
setcookie('rememberme', $cookie);
}
Kemudian, untuk memvalidasi:
function rememberMe() {
$cookie = isset($_COOKIE['rememberme']) ? $_COOKIE['rememberme'] : '';
if ($cookie) {
list ($user, $token, $mac) = explode(':', $cookie);
if (!hash_equals(hash_hmac('sha256', $user . ':' . $token, SECRET_KEY), $mac)) {
return false;
}
$usertoken = fetchTokenByUserName($user);
if (hash_equals($usertoken, $token)) {
logUserIn($user);
}
}
}
Catatan: Jangan gunakan token atau kombinasi pengguna dan token untuk mencari catatan di database Anda. Selalu pastikan untuk mengambil catatan berdasarkan pengguna dan menggunakan fungsi perbandingan aman-waktu untuk membandingkan token yang diambil setelahnya. Lebih lanjut tentang serangan waktu .
Sekarang, sangat penting bahwa SECRET_KEY
rahasia kriptografi (dihasilkan oleh sesuatu seperti /dev/urandom
dan / atau berasal dari input entropi tinggi). Juga, GenerateRandomToken()
harus menjadi sumber acak yang kuat ( mt_rand()
tidak hampir cukup kuat. Gunakan perpustakaan, seperti RandomLib atau random_compat , atau mcrypt_create_iv()
dengan DEV_URANDOM
) ...
The hash_equals()
adalah untuk mencegah serangan waktu . Jika Anda menggunakan versi PHP di bawah PHP 5.6 fungsi hash_equals()
tidak didukung. Dalam hal ini Anda dapat mengganti hash_equals()
dengan fungsi timingSafeCompare:
/**
* A timing safe equals comparison
*
* To prevent leaking length information, it is important
* that user input is always used as the second parameter.
*
* @param string $safe The internal (safe) value to be checked
* @param string $user The user submitted (unsafe) value
*
* @return boolean True if the two strings are identical.
*/
function timingSafeCompare($safe, $user) {
if (function_exists('hash_equals')) {
return hash_equals($safe, $user); // PHP 5.6
}
// Prevent issues if string length is 0
$safe .= chr(0);
$user .= chr(0);
// mbstring.func_overload can make strlen() return invalid numbers
// when operating on raw binary strings; force an 8bit charset here:
if (function_exists('mb_strlen')) {
$safeLen = mb_strlen($safe, '8bit');
$userLen = mb_strlen($user, '8bit');
} else {
$safeLen = strlen($safe);
$userLen = strlen($user);
}
// Set the result to the difference between the lengths
$result = $safeLen - $userLen;
// Note that we ALWAYS iterate over the user-supplied length
// This is to prevent leaking length information
for ($i = 0; $i < $userLen; $i++) {
// Using % here is a trick to prevent notices
// It's safe, since if the lengths are different
// $result is already non-0
$result |= (ord($safe[$i % $safeLen]) ^ ord($user[$i]));
}
// They are only identical strings if $result is exactly 0...
return $result === 0;
}
Biasanya saya melakukan sesuatu seperti ini:
Tentu saja Anda dapat menggunakan nama cookie yang berbeda, dll. Anda juga dapat sedikit mengubah isi cookie, tapi pastikan itu tidak mudah dibuat. Misalnya, Anda juga dapat membuat user_salt saat pengguna dibuat dan juga memasukkannya ke dalam cookie.
Anda juga dapat menggunakan sha1 bukan md5 (atau cukup banyak algoritma apa pun)
sumber
pengantar
Judul Anda “Tetap Tercatat Saya” - pendekatan terbaik mempersulit saya untuk tahu harus mulai dari mana karena jika Anda mencari pendekatan terbaik maka Anda harus mempertimbangkan hal-hal berikut:
Kue
Cookie rentan, Antara kerentanan pencurian cookie pada browser umum dan serangan skrip lintas situs, kami harus menerima bahwa cookie tidak aman. Untuk membantu meningkatkan keamanan, Anda harus perhatikan bahwa
php
setcookies
ada fungsi tambahan sepertiDefinisi
Pendekatan Sederhana
Solusi sederhana adalah:
Studi kasus di atas merangkum semua contoh yang diberikan pada halaman ini tetapi kekurangannya adalah itu
Solusi yang lebih baik
Solusi yang lebih baik
Kode Contoh
Kelas yang digunakan
Menguji di Firefox & Chrome
Keuntungan
Kerugian
Perbaikan Cepat
Berbagai Pendekatan Cookie
Ketika seorang penyerang akan mencuri cookie, fokus saja pada situs web atau domain tertentu misalnya. example.com
Tapi sungguh Anda dapat mengautentikasi pengguna dari 2 domain berbeda ( example.com & fakeaddsite.com ) dan membuatnya seperti "Iklan Cookie"
Beberapa orang mungkin bertanya-tanya bagaimana Anda bisa menggunakan 2 cookie yang berbeda? Yah itu mungkin, bayangkan
example.com = localhost
danfakeaddsite.com = 192.168.1.120
. Jika Anda memeriksa cookie itu akan terlihat seperti iniDari gambar di atas
192.168.1.120
HTTP_REFERER
REMOTE_ADDR
Keuntungan
Kerugian
Perbaikan
ajax
sumber
Saya menanyakan satu sudut pertanyaan ini di sini , dan jawabannya akan mengarahkan Anda ke semua tautan cookie penghitungan waktu token yang Anda butuhkan.
Pada dasarnya, Anda tidak menyimpan ID pengguna dalam cookie. Anda menyimpan token satu kali (string besar) yang digunakan pengguna untuk mengambil sesi login lama mereka. Kemudian untuk membuatnya benar-benar aman, Anda meminta kata sandi untuk operasi berat (seperti mengubah kata sandi itu sendiri).
sumber
Utas lama, namun masih menjadi perhatian yang valid. Saya memperhatikan beberapa tanggapan yang baik tentang keamanan, dan menghindari penggunaan 'keamanan melalui ketidakjelasan', tetapi metode teknis yang sebenarnya diberikan tidak cukup di mata saya. Hal-hal yang harus saya katakan sebelum berkontribusi metode saya:
Itu semua dikatakan, ada dua cara bagus untuk memiliki masuk otomatis pada sistem Anda.
Pertama, cara murah dan mudah yang menempatkan semuanya pada orang lain. Jika Anda membuat situs Anda mendukung login dengan, katakanlah, akun Google + Anda, Anda mungkin memiliki tombol google + ramping yang akan masuk pengguna jika mereka sudah masuk ke google (saya melakukan itu di sini untuk menjawab pertanyaan ini, karena saya selalu masuk ke google). Jika Anda ingin pengguna masuk secara otomatis jika mereka sudah masuk dengan autentikator yang tepercaya dan didukung, dan centang kotak untuk melakukannya, minta skrip sisi klien Anda melakukan kode di belakang tombol 'masuk dengan' yang sesuai sebelum memuat , pastikan server menyimpan ID unik di tabel masuk otomatis yang memiliki nama pengguna, ID sesi, dan autentikator yang digunakan untuk pengguna. Karena metode masuk ini menggunakan AJAX, Anda tetap menunggu respons, dan respons itu adalah respons tervalidasi atau penolakan. Jika Anda mendapatkan respons yang divalidasi, gunakan seperti biasa, lalu lanjutkan memuat pengguna yang masuk seperti biasa. Jika tidak, login gagal, tetapi jangan beri tahu pengguna, terus saja karena tidak masuk, mereka akan melihat. Ini untuk mencegah penyerang yang mencuri cookie (atau memalsunya dalam upaya untuk meningkatkan hak istimewa) dari mengetahui bahwa pengguna secara otomatis masuk ke situs.
Ini murah, dan mungkin juga dianggap kotor oleh beberapa orang karena mencoba memvalidasi diri Anda yang berpotensi sudah masuk sendiri dengan tempat-tempat seperti Google dan Facebook, bahkan tanpa memberi tahu Anda. Namun, itu tidak boleh digunakan pada pengguna yang belum meminta untuk masuk otomatis ke situs Anda, dan metode khusus ini hanya untuk otentikasi eksternal, seperti dengan Google+ atau FB.
Karena autentikator eksternal digunakan untuk memberi tahu server di balik layar apakah seorang pengguna divalidasi atau tidak, penyerang tidak dapat memperoleh apa pun selain ID unik, yang tidak berguna dengan sendirinya. Saya akan menguraikan:
Tidak peduli apa, bahkan jika penyerang menggunakan ID yang tidak ada, upaya harus gagal pada semua upaya kecuali ketika respons yang divalidasi diterima.
Metode ini dapat dan harus digunakan bersama dengan autentikator internal Anda bagi mereka yang masuk ke situs Anda menggunakan autentikator eksternal.
=========
Sekarang, untuk sistem autentikator Anda sendiri yang dapat secara otomatis masuk pengguna, ini adalah bagaimana saya melakukannya:
DB memiliki beberapa tabel:
Perhatikan bahwa nama pengguna dapat mencapai 255 karakter. Saya memiliki program server saya membatasi nama pengguna di sistem saya menjadi 32 karakter, tetapi autentikator eksternal mungkin memiliki nama pengguna dengan @ domain.tld mereka lebih besar dari itu, jadi saya hanya mendukung panjang maksimum alamat email untuk kompatibilitas maksimum.
Perhatikan bahwa tidak ada bidang pengguna dalam tabel ini, karena nama pengguna, ketika login, ada di data sesi, dan program tidak mengizinkan data nol. The session_id dan session_token dapat dihasilkan menggunakan hash md5 acak, hash sha1 / 128/256, stempel datetime dengan string acak ditambahkan ke mereka kemudian hash, atau apa pun yang Anda inginkan, tetapi entropi output Anda harus tetap setinggi yang dapat ditoleransi untuk mengurangi serangan brute-force bahkan setelah turun dari tanah, dan semua hash yang dihasilkan oleh kelas sesi Anda harus diperiksa untuk pertandingan di tabel sesi sebelum mencoba menambahkannya.
Alamat MAC menurut sifatnya seharusnya UNIK, oleh karena itu masuk akal bahwa setiap entri memiliki nilai unik. Hostnames, di sisi lain, dapat diduplikasi di jaringan terpisah secara sah. Berapa banyak orang yang menggunakan "Home-PC" sebagai salah satu nama komputer mereka? Nama pengguna diambil dari data sesi oleh server backend, jadi memanipulasi itu tidak mungkin. Adapun token, metode yang sama untuk menghasilkan token sesi untuk halaman harus digunakan untuk menghasilkan token di cookie untuk pengguna masuk otomatis pengguna. Terakhir, kode datetime ditambahkan ketika pengguna perlu memvalidasi ulang kredensial mereka. Entah perbarui datetime ini pada login pengguna yang menyimpannya dalam beberapa hari, atau paksakan untuk kedaluwarsa terlepas dari login terakhir yang menyimpannya hanya selama sebulan atau lebih, mana pun yang ditentukan oleh desain Anda.
Ini mencegah seseorang dari spoofing MAC secara sistematis dan nama host untuk pengguna yang mereka kenal masuk otomatis. TIDAK PERNAHminta pengguna menyimpan cookie dengan kata sandi, menghapus teks atau sebaliknya. Buat token diregenerasi pada setiap navigasi halaman, sama seperti Anda melakukan token sesi. Ini secara besar-besaran mengurangi kemungkinan penyerang bisa mendapatkan cookie token yang valid dan menggunakannya untuk login. Beberapa orang akan mencoba mengatakan bahwa seorang penyerang dapat mencuri cookie dari korban dan melakukan serangan replay sesi untuk login. Jika penyerang bisa mencuri cookie (yang mungkin), mereka pasti akan membahayakan seluruh perangkat, yang berarti mereka bisa saja menggunakan perangkat untuk login, yang mengalahkan tujuan mencuri cookie sepenuhnya. Selama situs Anda menggunakan HTTPS (yang seharusnya ketika berhadapan dengan kata sandi, nomor CC, atau sistem masuk lainnya), Anda telah memberikan semua perlindungan kepada pengguna yang Anda bisa dalam browser.
Satu hal yang perlu diingat: data sesi tidak boleh kedaluwarsa jika Anda menggunakan masuk otomatis. Anda dapat kedaluwarsa kemampuan untuk melanjutkan sesi dengan salah, tetapi memvalidasi ke dalam sistem harus melanjutkan data sesi jika itu adalah data persisten yang diharapkan untuk berlanjut di antara sesi. Jika Anda menginginkan data sesi persisten dan non-persisten, gunakan tabel lain untuk data sesi persisten dengan nama pengguna sebagai PK, dan minta server mengambilnya seperti data sesi normal, cukup gunakan variabel lain.
Setelah masuk dengan cara ini, server masih harus memvalidasi sesi. Di sinilah Anda bisa memberi kode harapan untuk sistem yang dicuri atau dikompromikan; pola dan hasil lain yang diharapkan dari login ke data sesi sering dapat mengarah pada kesimpulan bahwa suatu sistem dibajak atau cookie dipalsukan untuk mendapatkan akses. Di sinilah Tek ISS Anda dapat menetapkan aturan yang akan memicu penguncian akun atau penghapusan otomatis pengguna dari sistem masuk otomatis, membuat penyerang keluar cukup lama bagi pengguna untuk menentukan bagaimana penyerang berhasil dan cara memotongnya.
Sebagai catatan penutup, pastikan bahwa setiap upaya pemulihan, perubahan kata sandi, atau kegagalan login melewati ambang batas mengakibatkan penandatanganan otomatis dinonaktifkan hingga pengguna memvalidasi dengan benar dan mengakui hal ini telah terjadi.
Saya minta maaf jika ada yang mengharapkan kode untuk diberikan dalam jawaban saya, itu tidak akan terjadi di sini. Saya akan mengatakan bahwa saya menggunakan PHP, jQuery, dan AJAX untuk menjalankan situs saya, dan saya TIDAK PERNAH menggunakan Windows sebagai server ... selamanya.
sumber
Saya akan merekomendasikan pendekatan yang disebutkan oleh Stefan (yaitu ikuti panduan dalam Praktek Terbaik Cookie Persistent Improved Login ) dan juga merekomendasikan agar Anda memastikan cookie Anda adalah cookie HttpOnly sehingga mereka tidak dapat diakses oleh, yang berpotensi berbahaya, JavaScript.
sumber
Hasilkan hash, mungkin hanya dengan rahasia yang Anda tahu, lalu simpan di DB Anda sehingga dapat dikaitkan dengan pengguna. Harus bekerja dengan baik.
sumber
Solusi saya seperti ini. Ini bukan 100% anti peluru, tapi saya pikir itu akan menyelamatkan Anda untuk sebagian besar kasus.
Ketika pengguna masuk berhasil membuat string dengan informasi ini:
Enkripsi
$data
, atur tipe ke HttpOnly dan atur cookie.Ketika pengguna kembali ke situs Anda, Buat langkah-langkah ini:
:
karakter.Jika pengguna keluar, hapus cookie ini. Buat cookie baru jika pengguna masuk kembali.
sumber
Saya tidak mengerti konsep menyimpan hal-hal terenkripsi dalam cookie ketika itu adalah versi terenkripsi yang Anda butuhkan untuk melakukan peretasan. Jika saya kehilangan sesuatu, silakan komentar.
Saya sedang berpikir untuk mengambil pendekatan ini ke 'Remember Me'. Jika Anda dapat melihat masalah apa pun, silakan komentar.
Buat tabel untuk menyimpan data "Ingat Saya" di - pisahkan dengan tabel pengguna sehingga saya bisa masuk dari beberapa perangkat.
Saat login berhasil (dengan Ingat Saya):
a) Hasilkan string acak unik untuk digunakan sebagai UserID pada mesin ini: bigUserID
b) Menghasilkan string acak yang unik: bigKey
c) Simpan cookie: bigUserID: bigKey
d) Dalam tabel "Remember Me", tambahkan catatan dengan: UserID, Alamat IP, bigUserID, bigKey
Jika mencoba mengakses sesuatu yang memerlukan login:
a) Periksa cookie dan cari bigUserID & bigKey dengan alamat IP yang cocok
b) Jika Anda menemukannya, Log orang tersebut tetapi tetapkan bendera di tabel pengguna "login lunak" sehingga untuk operasi berbahaya, Anda dapat meminta login penuh.
Saat logout, Tandai semua catatan "Ingat Saya" untuk pengguna itu sebagai kedaluwarsa.
Satu-satunya kerentanan yang bisa saya lihat adalah;
sumber
Saya membaca semua jawaban dan masih kesulitan untuk mengekstrak apa yang seharusnya saya lakukan. Jika gambar bernilai 1rb kata, saya harap ini membantu orang lain menerapkan penyimpanan persisten yang aman berdasarkan Praktek Terbaik Cookie Persisten yang Ditingkatkan Barry Jaspan
Jika Anda memiliki pertanyaan, umpan balik, atau saran, saya akan mencoba memperbarui diagram untuk mencerminkan bagi pemula yang mencoba menerapkan login persisten yang aman.
sumber
Menerapkan fitur "Keep Me Logged In" berarti Anda harus menentukan dengan tepat apa artinya bagi pengguna. Dalam kasus paling sederhana, saya akan menggunakan itu berarti sesi memiliki batas waktu lebih lama: 2 hari (katakanlah) daripada 2 jam. Untuk melakukan itu, Anda akan memerlukan penyimpanan sesi Anda sendiri, mungkin dalam database, sehingga Anda dapat mengatur waktu kedaluwarsa khusus untuk data sesi. Maka Anda perlu memastikan bahwa Anda menetapkan cookie yang akan bertahan selama beberapa hari (atau lebih lama), daripada kedaluwarsa ketika mereka menutup browser.
Saya dapat mendengar Anda bertanya "mengapa 2 hari? Mengapa tidak 2 minggu?". Ini karena menggunakan sesi dalam PHP akan secara otomatis mendorong kedaluwarsa kembali. Ini karena kedaluwarsa sesi dalam PHP sebenarnya adalah waktu tunggu idle.
Sekarang, setelah mengatakan itu, saya mungkin akan menerapkan nilai batas waktu lebih keras yang saya simpan di sesi itu sendiri, dan keluar pada 2 minggu atau lebih, dan menambahkan kode untuk melihat itu dan untuk secara paksa membatalkan sesi. Atau setidaknya untuk log out. Ini berarti bahwa pengguna akan diminta untuk masuk secara berkala. Yahoo! Melakukan hal ini.
sumber
Saya pikir Anda bisa melakukan ini:
Toko
$cookiestring
di DB dan dan tetapkan sebagai cookie. Juga tetapkan nama pengguna orang tersebut sebagai cookie. Inti dari hash adalah tidak dapat direkayasa ulang.Saat pengguna muncul, dapatkan nama pengguna dari satu cookie, daripada
$cookieString
dari yang lain. Jika$cookieString
cocok dengan yang disimpan dalam DB, maka pengguna diautentikasi. Karena password_hash menggunakan garam yang berbeda setiap kali, itu tidak relevan untuk apa teks yang jelas itu.sumber