Log masuk dengan CFML: kata laluan, sesi dan keselamatan dalam satu fail
Kata laluan tidak boleh disimpan sebagai teks biasa, dan sesi tidak akan berfungsi tanpa dua tetapan yang betul. Tutorial ini menunjukkan kedua-duanya, dengan kod yang boleh dicuba terus dan dimuat turun.
Borang log masuk ialah tugasan pertama yang perlu difahami oleh setiap pembangun web, dan juga tugasan yang paling banyak disalah tulis. Masalahnya bukan borangnya. Masalahnya ialah apa yang berlaku kepada kata laluan itu selepas butang ditekan.
Tutorial ini membina satu sistem log masuk yang lengkap dalam satu fail: daftar akaun, log masuk, kawasan yang hanya kelihatan selepas masuk, dan keluar. Semuanya menggunakan teg CFML asas, dan setiap bahagian dalam tutorial ini sudah pun dicuba pada aplikasi sebenar sebelum ia ditulis di sini, supaya kod yang awak salin benar-benar berjalan.
Aplikasi yang dibina boleh dicuba terus, dan kodnya boleh dimuat turun. Data demo dikosongkan sendiri, jadi jangan guna kata laluan sebenar awak di situ.
Perkara paling penting: kata laluan tidak pernah disimpan
Hampir setiap tutorial menunjukkan baris ini, dan hampir setiap tutorial berhenti di situ.
<cfset cincang = hash( kata, "SHA-256" )>
Baris itu berkesan, tetapi ia tidak selamat untuk kata laluan. Angka di bawah ini diukur pada satu pelayan kecil, dan ia menunjukkan masalahnya dengan jelas.
- SHA-256 sekali sahaja: kira-kira 1,250,000 cincang sesaat, walaupun dijalankan dalam CFML atas mesin yang sederhana.
- SHA-256 yang sama, diulang 100,000 kali: kira-kira 12 percubaan sesaat.
Perbezaannya 100,000 kali ganda, dan ia bahasa yang sama. Sebabnya mudah. Cincang biasa direka supaya pantas, kerana komputer perlu mengesahkan fail besar dengan pantas. Untuk kata laluan, kepantasan itulah musuhnya. Penyerang yang berjaya mencuri jadual pengguna boleh mencuba berjuta-juta teka-teki sesaat ke atas cincang yang pantas, dan berjuta-juta teka-teki itu cukup untuk memecahkan kata laluan yang lemah dalam masa yang singkat.
Cara yang betul ialah mengulanginya, dan menambahkan garam, iaitu nilai rawak yang berbeza bagi setiap pengguna. Garam bermaksud dua orang yang menggunakan kata laluan yang sama tetap mempunyai cincang yang berbeza.
<!--- garam rawak untuk setiap pengguna --->
<cfset garam = generateSecretKey( "AES" )>
<!--- SHA-256 diulang 100,000 kali (PBKDF2) --->
<cfset cincang = generatePBKDFKey( "PBKDF2WithHmacSHA256", kata, garam, 100000, 256 )>
Jadual: apa yang perlu disimpan
Perhatikan tiga medan untuk kata laluan, bukan satu. Ini disengajakan, kerana garam dan bilangan putaran perlu disimpan bersama cincang supaya ia boleh disahkan kemudian, dan supaya ia boleh dinaikkan pada masa hadapan tanpa memaksa semua orang menukar kata laluan.
CREATE TABLE demo_pengguna (
id INT AUTO_INCREMENT PRIMARY KEY,
nama VARCHAR(60) NOT NULL,
emel VARCHAR(120) NOT NULL,
kata_hash VARCHAR(120) NOT NULL,
garam VARCHAR(60) NOT NULL,
putaran INT NOT NULL,
cubaan INT NOT NULL DEFAULT 0,
sekat_sehingga DATETIME NULL,
dicipta DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uniq_emel (emel)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Medan cubaan dan sekat_sehingga mengira percubaan log masuk yang salah. Medan UNIQUE pada emel pula memastikan satu emel hanya boleh didaftarkan sekali, dan ia melindungi sistem daripada dua akaun yang sama yang dicipta serentak.
Mendaftar: sahkan dahulu, simpan kemudian
<cfset nama = trim( form.nama )>
<cfset emel = lcase( trim( form.emel ) )>
<cfset kata = form.kata>
<cfif len( nama ) lt 2>
<cfset mesej = "Nama mesti antara 2 hingga 60 aksara.">
<cfelseif not reFind( "^[^@\s]+@[^@\s]+\.[a-zA-Z]{2,}$", emel )>
<cfset mesej = "Emel itu tidak sah.">
<cfelseif len( kata ) lt 8>
<cfset mesej = "Kata laluan mesti sekurang-kurangnya 8 aksara.">
<cfelse>
<!--- garam, cincang, kemudian simpan --->
</cfif>
Tiga perkara dalam kod ini yang berbaloi diperhatikan. Pertama, emel ditukar kepada huruf kecil supaya Ali@Contoh.my dan ali@contoh.my dianggap sama. Kedua, panjang minimum kata laluan ialah lapan aksara, dan had itu lebih berguna daripada peraturan kerumitan yang menyusahkan orang. Ketiga, ungkapan yang menyemak bentuk emel itu sengaja ringkas. Pengesahan emel yang sempurna memerlukan penghantaran e-mel sebenar, dan itu perkara lain.
Log masuk: membandingkan kata laluan
Cincang tidak boleh diterbalikkan, jadi kata laluan yang tersimpan tidak boleh dibaca semula. Apa yang berlaku semasa log masuk ialah kata laluan yang ditaip dicincang semula, menggunakan garam dan putaran yang sama, kemudian dua cincang itu dibandingkan.
<cfquery name="qCari" datasource="biz">
SELECT id, nama, kata_hash, garam, putaran
FROM demo_pengguna
WHERE emel = <cfqueryparam value="#emel#" cfsqltype="cf_sql_varchar" maxlength="120">
</cfquery>
<cfset cincangCuba = generatePBKDFKey( "PBKDF2WithHmacSHA256", kata, qCari.garam, qCari.putaran, 256 )>
<cfif cincangCuba eq qCari.kata_hash>
<!--- kata laluan betul --->
</cfif>
Ralat yang sama untuk dua keadaan berbeza
Ini satu baris yang kelihatan remeh, tetapi ia membezakan sistem yang faham keselamatan daripada yang tidak. Apabila log masuk gagal, mesejnya mestilah sama, sama ada emel itu tidak wujud atau kata laluannya salah.
<cfset mesej = "Emel atau kata laluan tidak sepadan.">
Sebabnya mudah. Kalau sistem memberitahu "emel itu tiada" apabila emel tidak dikenali, sesiapa sahaja boleh menggunakan borang awak untuk menyemak emel mana yang berdaftar. Ia dipanggil pendedahan maklumat melalui mesej ralat, dan ia langkah pertama dalam serangan yang menyasarkan akaun tertentu.
Sesi: bagaimana sistem mengingati pengguna
Selepas log masuk berjaya, sistem perlu mengingati pengguna itu antara satu halaman dengan halaman seterusnya. Mekanisme itu dipanggil sesi, dan dalam CFML ia disimpan dalam skop session.
<cfset session.penggunaId = qCari.id>
<cfset session.nama = qCari.nama>
<cfset session.emel = emel>
Sesi bermakna pelayan yang mengingati, bukan pelayar. Pelayar hanya menyimpan satu penanda kecil, dan penanda itulah yang menentukan sesi mana milik siapa. Ini jauh lebih selamat daripada menyimpan status log masuk dalam kuki yang boleh dibaca dan diubah oleh pengguna.
Keluar, dan menukar id sesi
Keluar bukan sekadar memadam pemboleh ubah. Ia perlu mengosongkan keseluruhan skop sesi, dan menukar id sesi itu sendiri.
<cfset structClear( session )>
<cfset sessionRotate()>
<cflocation url="/demo/log-masuk?ok=keluar" addtoken="no">
Kenapa perlu menukar id sesi. Bayangkan seseorang berjaya menghantar satu pautan yang mengandungi id sesi awak kepada awak, dan awak membukanya. Kalau id sesi tidak pernah berubah selepas log masuk, penyerang itu kini memegang id yang sah. Amalan yang betul ialah menukar id sesi sebaik sahaja identiti pengguna berubah, iaitu semasa log masuk dan semasa keluar. Fungsi sessionRotate itu yang melakukannya.
Melambatkan percubaan meneka
Kata laluan yang kukuh tidak berguna kalau seseorang boleh mencuba berjuta-juta kombinasi melalui borang. Jadi borang log masuk perlu melambatkan percubaan itu.
<cfset MAKS_CUBAAN = 5>
<cfset SEKAT_MINIT = 15>
<!--- selepas kata laluan salah --->
<cfset cubaanBaru = qCari.cubaan + 1>
<cfif cubaanBaru gte MAKS_CUBAAN>
<!--- set sekat_sehingga = sekarang + 15 minit --->
</cfif>
Dalam kod ini, lima percubaan salah akan menyekat akaun itu selama lima belas minit. Sepanjang tempoh itu, kata laluan yang betul pun tetap ditolak. Itulah maksudnya: sekatan tidak boleh dipintas dengan meneka sekali lagi. Perhatikan satu perkara penting, iaitu had itu dikira pada akaun, bukan hanya pada alamat IP, kerana penyerang boleh menukar alamat IP dengan mudah.
Empat perkara lain yang selalu dilupakan
- Kodkan setiap nilai sebelum dipaparkan. Nama pengguna boleh mengandungi kod, dan kod yang dipaparkan mentah boleh dijalankan oleh pelayar orang lain.
- Jangan catat kata laluan dalam fail log. Ia kedengaran jelas, tetapi ia berlaku kerana orang mencatat keseluruhan borang semasa menyiasat masalah.
- Gunakan HTTPS. Tanpa ia, kata laluan dihantar dalam bentuk yang boleh dibaca di tengah jalan, dan semua kerja cincang tadi menjadi tidak berguna.
- Kuki sesi perlu ditanda Secure supaya ia tidak dihantar melalui sambungan tidak selamat, HttpOnly supaya kod dalam halaman tidak boleh membacanya, dan SameSite supaya ia tidak dihantar dari laman lain tanpa kebenaran awak.
Apa yang perlu awak uji pada borang awak sendiri
Setiap perkara di atas diuji melalui alamat awam, bukan dibaca daripada kod. Ujian itu mencipta akaun, mencuba kata laluan salah, log masuk dengan betul, keluar, menyekat akaun selepas lima percubaan, dan menghantar teks suntikan SQL dalam medan emel. Semuanya lulus, dan kata laluan tidak pernah muncul dalam jadual.
Cuba sendiri
Apa yang perlu ditambah sebelum ia digunakan oleh orang sebenar
Kod dalam tutorial ini lengkap untuk belajar, dan ia selamat dalam perkara-perkara asas. Tetapi ia belum menjadi sistem akaun yang lengkap, dan perbezaannya berbaloi difahami supaya awak tidak menyangka ia sudah siap.
- Lupa kata laluan. Setiap sistem sebenar memerlukannya. Ia mesti melalui e-mel, dan pautan pemulihan itu mesti luput dalam masa yang singkat serta hanya boleh digunakan sekali.
- Pengesahan emel. Tanpa ia, sesiapa sahaja boleh mendaftar menggunakan emel orang lain, dan orang itu tidak pernah tahu.
- Catatan audit. Sistem sebenar perlu merekod siapa masuk, bila, dan dari mana, supaya kejadian luar biasa boleh disiasat kemudian.
- Log keluar automatik. Sesi dalam kod ini tamat selepas 30 minit tanpa aktiviti. Untuk sistem yang menyimpan data sensitif, tempoh itu perlu dipendekkan, dan pengguna perlu dimaklumkan sebelum ia tamat.
- Pengesahan dua langkah. Ia menambah satu langkah, dan ia menghalang sebahagian besar serangan yang menggunakan kata laluan yang dicuri.
- Semakan kata laluan yang pernah bocor. Kalau kata laluan itu muncul dalam senarai kebocoran awam, sistem boleh menolaknya semasa pendaftaran.
Susunan yang dicadangkan ialah tambah lupa kata laluan dan pengesahan e-mel dahulu, kerana kedua-duanya berkaitan dengan kepercayaan pengguna. Catatan audit datang selepas itu, kerana ia lebih berguna apabila sudah ada sesuatu yang perlu disiasat.
Halaman contoh itu boleh dicuba terus, dan kod penuhnya boleh dimuat turun bersama skrip jadual dan arahan pemasangan. Kalau awak mahu mengikuti urutan yang sama seperti siri ini, mulakan dengan tutorial CRUD dahulu, kerana log masuk ialah lapisan di atas corak yang sama.
Halaman ini dicetak tanpa menu, borang langgan dan jalur sisi.
Baca juga di laman ini
- CRUD dengan CFML menggunakan teg asas: tutorial untuk pemula mula di sini kalau corak asas belum difahami
- Keselamatan CFML: CVE sebenar, dan cara mengukuhkan pelayan lapisan seterusnya selepas aplikasi ditulis
- Belajar ColdFusion pada 2026: laluan, sumber dan kesilapan pemula urutan belajar keseluruhan
Sumber yang disemak
Maklumat dalam tulisan ini disemak dengan sumber di bawah. Bila keadaan berubah (harga, waktu, terma), sumber inilah yang paling tepat — bukan halaman ini.
Dapat tulisan baharu terus ke e-mel
Sekali sekala sahaja: panduan web, berita AI, dan tempat menarik di Kelantan. Tiada iklan, dan e-mel encik tidak dikongsi dengan sesiapa.