Tutorial Pasukan Lucee MY

Pengesahan Pengguna dalam CFML: Kata Laluan, Sesi dan 2FA

Panduan pengesahan pengguna CFML: simpan kata laluan dengan bcrypt atau argon2, atur semula sesi untuk halang session fixation, dan tambah 2FA TOTP dalam Lucee.

Pengesahan Pengguna dalam CFML: Kata Laluan, Sesi dan 2FA
0
Kandungan

Pengesahan Pengguna dalam CFML: Kata Laluan, Sesi dan 2FA

Pengesahan pengguna yang kukuh dalam CFML berasaskan tiga lapisan: menyimpan kata laluan sebagai hash yang sukar dipecahkan, melindungi sesi selepas log masuk, dan menambah faktor kedua supaya kata laluan yang bocor tidak cukup untuk masuk. Lucee menyediakan fungsi khusus untuk ketiga-tiganya, daripada Argon2Hash() dan SessionRotate() sehinggalah HMAC() untuk membina pengesahan dua faktor TOTP. Artikel ini memandu anda menyusun ketiga-tiga lapisan itu langkah demi langkah dengan kod yang boleh anda sesuaikan terus.

Menyimpan Kata Laluan: Jangan Guna hash() Biasa

Kesilapan yang paling lazim ialah menggunakan hash() untuk kata laluan. Fungsi hash() dalam Lucee menyokong MD5, SHA-1, SHA-256, SHA-384 dan SHA-512, dan ia berguna untuk checksum atau pengesanan perubahan fail, bukan untuk kata laluan. Masalahnya dua: algoritma ini pantas secara sengaja, jadi penyerang boleh mencuba berjuta-juta tekaan sesaat, dan ia tidak membawa garam (salt) secara automatik. Cheat Sheet Penyimpanan Kata Laluan OWASP mengesyorkan algoritma khas yang direka untuk menjadi perlahan dan mahal: Argon2id sebagai pilihan utama, diikuti bcrypt, scrypt dan PBKDF2, semuanya dengan faktor kerja yang sengaja memperlahankan pengiraan.

BCrypt dan Argon2 dalam Lucee

Lucee menyediakan fungsi khas untuk kedua-dua algoritma ini, jadi anda tidak perlu menulis pelaksanaan hash sendiri. Argon2Hash() menjana hash dengan lalai yang disyorkan OWASP, iaitu argon2id dengan memori 19 MB dan dua lelaran. BCryptHash() pula menerima parameter kos yang mengawal bilangan lelaran. Contoh menyimpan dan menyemak kata laluan:

// Menyimpan kata laluan baru, contohnya semasa pendaftaran
var passwordHash = Argon2Hash(form.password);       // argon2id, 19 MB, 2 lelaran
// atau bcrypt dengan faktor kerja
var passwordHash = BCryptHash(form.password, 12);   // kos 12

// Menyemak semasa log masuk
if (Argon2Verify(form.password, storedHash)) {
    // Sah, teruskan ke langkah seterusnya
} else {
    // Tolak: kata laluan salah
}

Jangan sekali-kali menyimpan kata laluan sebagai teks biasa atau membandingkan nilai secara terus. Argon2Verify() dan BCryptVerify() memulangkan boolean dan mengendalikan garam yang tersimpan di dalam hash itu sendiri, jadi anda cuma perlu simpan satu nilai. Perhatikan bahawa GenerateArgon2Hash() yang lama wujud tetapi menggunakan lalai yang lemah (argon2i, memori 8 KB, satu lelaran), manakala VerifyBCryptHash() dan Argon2CheckHash() pula sudah ditandakan lapuk. Untuk kod baharu, gunakan Argon2Hash() dan Argon2Verify().

Memilih Algoritma dan Faktor Kerja

Jadual berikut merumuskan pilihan anda dan fungsi yang sepadan:

AlgoritmaFungsi hashFungsi semakCatatan
Argon2idArgon2Hash()Argon2Verify()Lalai OWASP: 19 MB, 2 lelaran
bcryptBCryptHash(input, kos)BCryptVerify()Kos 10 hingga 12 lazim digunakan
SHA-256 (hash())hash(input, "SHA-256")tiadaUntuk checksum, bukan kata laluan

Faktor kerja ialah penimbal melawan kemajuan perkakasan: nilai yang terasa pantas hari ini akan menjadi terlalu murah dalam beberapa tahun. Semak semula kos bcrypt atau parameter argon2 anda secara berkala dan naikkannya apabila pelayan anda mampu.

Menetapkan Semula Sesi Selepas Log Masuk

Session fixation ialah serangan di mana penyerang menetapkan ID sesi tertentu kepada pelayar mangsa sebelum mangsa log masuk. Jika aplikasi mengekalkan ID sesi yang sama selepas pengesahan berjaya, penyerang yang tahu ID itu boleh terus masuk sebagai mangsa. Ubatnya mudah: jana ID sesi baharu pada saat log masuk, supaya ID lama yang diketahui penyerang menjadi tidak berguna.

Lucee menyediakan SessionRotate() untuk tujuan ini. Ia mencipta sesi baharu dengan token segar, menyalin data sedia ada, dan mematikan token lama:

// Selepas kata laluan dan 2FA disahkan
SessionRotate();               // token baharu, data lama disalin, token lama dibatalkan
session.userID = qUser.userID; // tetapkan data sesi selepas putaran

Semasa log keluar, gunakan SessionInvalidate() pula, kerana ia menamatkan sesi dan membuang semua data. Kedua-dua fungsi ini menghapuskan risiko membawa sesi yang telah terdedah ke dalam keadaan yang dipercayai. Untuk asas bagaimana sesi berfungsi dalam Lucee, rujuk panduan pengurusan sesi.

Kuki Sesi yang Selamat

Kuki yang membawa ID sesi mesti dilindungi supaya ia tidak dibaca atau dihantar secara cuai. Tetapkan tiga bendera pada kuki sesi: httpOnly supaya JavaScript tidak dapat membacanya, secure supaya ia hanya dihantar melalui HTTPS, dan sameSite untuk mengurangkan risiko CSRF. Dalam Application.cfc, anda boleh menetapkan ini sekali untuk keseluruhan aplikasi:

// Application.cfc
this.sessionCookie = { httpOnly: true, secure: true, sameSite: "lax" };

Bendera secure hanya berkesan apabila aplikasi anda berjalan di atas HTTPS, jadi pastikan sijil anda disediakan dengan betul. Bendera ini menutup laluan kecurian kuki melalui skrip atau sambungan tidak disulitkan, dan ia melengkapkan token CSRF yang dibincangkan dalam panduan keselamatan aplikasi web CFML.

Pengesahan Dua Faktor dengan TOTP

Kata laluan boleh bocor melalui pancingan data, pelanggaran pangkalan data pihak ketiga, atau tekaan. Pengesahan dua faktor menambah kod enam digit yang berubah setiap 30 saat mengikut piawaian TOTP (RFC 6238), yang dijana daripada rahsia yang disimpan di peranti pengguna. Lucee tidak mempunyai fungsi TOTP terbina dalam, tetapi anda boleh membinanya dengan HMAC(), yang memulangkan rentetan heksadesimal dan menyokong HmacSHA1, HmacSHA256 dan HmacSHA512:

// TOTP (RFC 6238). Sahkan kod terhadap aplikasi penjana seperti
// Google Authenticator semasa menguji, kerana butiran bait mesti tepat.
function totp(required string secretB32) {
    // 1. Nyahkod rahsia Base32 kepada bait
    var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
    var buffer = 0; var bits = 0; var key = [];
    secretB32 = uCase(replace(secretB32, "=", "", "all"));
    for (var i = 1; i <= len(secretB32); i++) {
        var v = find(mid(secretB32, i, 1), alphabet) - 1;
        if (v < 0) continue;
        buffer = bitOr(bitSHLN(buffer, 5), v);
        bits += 5;
        if (bits >= 8) { bits -= 8; arrayAppend(key, bitAnd(bitSHRN(buffer, bits), 255)); }
    }
    // 2. Kaunter 64-bit big-endian bagi tetingkap 30 saat
    var counter = int(now().getTime() / 30000);
    var msg = [];
    for (var j = 7; j >= 0; j--) { arrayAppend(msg, bitAnd(bitSHRN(counter, j * 8), 255)); }
    // 3. HMAC-SHA1, kemudian potongan dinamik (RFC 4226)
    var digest = binaryDecode(hmac(msg, key, "HmacSHA1"), "hex");
    var offset = bitAnd(digest[20], 15);
    var code = bitOr(bitOr(bitOr(
        bitSHLN(bitAnd(digest[offset + 1], 127), 24),
        bitSHLN(digest[offset + 2], 16)),
        bitSHLN(digest[offset + 3], 8)),
        digest[offset + 4]);
    return numberFormat(code % 1000000, "000000");
}

Apabila pengguna mengaktifkan 2FA, jana rahsia rawak, enkodkannya ke Base32, dan paparkan dalam bentuk kod QR bersama kunci simpanan. Simpan rahsia itu dengan selamat seperti mana-mana rahsia lain, seperti yang diterangkan dalam panduan mengurus rahsia CFML.

Mengunci Akaun Secara Berhemah

Kunci akaun kekal selepas beberapa percubaan gagal kedengaran selamat tetapi sebenarnya membuka pintu kepada serangan penafian perkhidmatan: penyerang boleh mengunci pemilik sebenar dengan sengaja menghantar kata laluan salah. Cheat Sheet Pengesahan OWASP menasihatkan supaya mencari keseimbangan antara keselamatan dan kebolehgunaan. Kunci berperingkat ialah jalan tengah: tempoh kunci bermula sangat singkat dan bertambah perlahan dengan setiap percubaan gagal berturut-turut, contohnya beberapa saat dahulu, kemudian minit. Ini cukup untuk menggagalkan serangan automatik tanpa mengunci pengguna sah secara kekal.

Had Kadar Log Masuk

Selain kunci akaun, had kadar memperlahankan jumlah cubaan secara keseluruhan. Ia berfungsi di peringkat IP atau akaun dan boleh digabungkan dengan kelewatan berperingkat supaya setiap percubaan gagal menjadi semakin lambat. Lapisan ini mengehadkan kerosakan walaupun penyerang menyasarkan banyak akaun sekaligus. Perincian penuh tentang had kadar dan perlindungan pelayan hadapan ada dalam panduan melindungi borang log masuk.

Menyatukan Semuanya: Aliran Log Masuk

Aliran log masuk yang lengkap seharusnya kelihatan seperti ini: sahkan kata laluan dengan Argon2Verify() atau BCryptVerify(), sahkan kod TOTP jika 2FA aktif, putar sesi dengan SessionRotate(), dan barulah tetapkan data sesi. Setiap langkah yang gagal dicatat dan dikira untuk had kadar. Apabila anda menyimpan rekod pengguna dan menyemak kelayakan terhadap pangkalan data, pastikan setiap nilai diikat sebagai parameter seperti yang diterangkan dalam panduan cfquery dan cfqueryparam.

Soalan Lazim (FAQ)

Apakah fungsi terbaik untuk hash kata laluan dalam Lucee?

Gunakan Argon2Hash() untuk kod baharu kerana ia menggunakan lalai yang disyorkan OWASP (argon2id, 19 MB, 2 lelaran). BCryptHash() dengan kos 10 hingga 12 ialah alternatif yang kukuh. Jangan guna hash() kerana ia pantas dan tidak sesuai untuk kata laluan.

Bagaimana saya menghalang session fixation dalam CFML?

Panggil SessionRotate() sebaik sahaja pengesahan berjaya. Ia mencipta sesi baharu dengan token segar dan mematikan token lama, supaya ID sesi yang diketahui penyerang menjadi tidak berguna.

Adakah saya perlu menulis pelaksanaan TOTP sendiri?

Tidak semestinya. Anda boleh membinanya dengan HMAC() seperti contoh di atas, tetapi untuk persekitaran pengeluaran, pertimbangkan pustaka yang telah disemak dan uji kod anda terhadap aplikasi penjana seperti Google Authenticator.

Apakah bendera kuki sesi yang wajib ditetapkan?

Tetapkan httpOnly, secure dan sameSite. Gabungan ini menghalang JavaScript membaca kuki, memaksa penghantaran melalui HTTPS, dan mengurangkan risiko CSRF.

Kenapa kunci akaun kekal itu tidak disyorkan?

Kerana penyerang boleh mengunci pemilik akaun yang sah dengan sengaja menghantar kata laluan salah, iaitu satu bentuk penafian perkhidmatan. Gunakan kunci berperingkat dengan tempoh yang bermula singkat dan bertambah perlahan.

Sumber

0 komen

Log masuk untuk menjawab atau memberi komen.

Log masuk