Sistem login terlihat sederhana: pengguna memasukkan email dan password lalu aplikasi memeriksa apakah datanya benar.
Namun autentikasi menyentuh data sensitif, sehingga implementasinya tidak boleh hanya mengejar fungsi. Password harus disimpan dengan benar, query harus aman, session perlu dikelola, dan pesan error tidak boleh membocorkan terlalu banyak informasi.
Prinsip Dasar Login yang Aman
- Jangan menyimpan password dalam bentuk teks biasa.
- Gunakan
password_hash(). - Verifikasi dengan
password_verify(). - Gunakan prepared statement.
- Regenerasi session ID setelah login.
- Gunakan HTTPS.
- Tambahkan CSRF protection pada aksi yang membutuhkan perlindungan.
1. Membuat Tabel Users
CREATE TABLE users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(190) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Kolom password dibuat cukup panjang karena hasil hash tidak sama dengan panjang password asli.
2. Membuat Password Hash
<?php
$password = "contoh-password";
$hash = password_hash(
$password,
PASSWORD_DEFAULT
);
echo $hash;
?>
Hash inilah yang disimpan di database. Jangan menyimpan password mentah.
3. Contoh Registrasi Sederhana
<?php
require __DIR__ . "/config/database.php";
$name = trim($_POST["name"] ?? "");
$email = trim($_POST["email"] ?? "");
$password = $_POST["password"] ?? "";
if (
$name === "" ||
!filter_var($email, FILTER_VALIDATE_EMAIL) ||
strlen($password) < 8
) {
exit("Data registrasi tidak valid.");
}
$passwordHash = password_hash(
$password,
PASSWORD_DEFAULT
);
$stmt = $pdo->prepare(
"INSERT INTO users (name, email, password_hash)
VALUES (:name, :email, :password_hash)"
);
$stmt->execute([
"name" => $name,
"email" => $email,
"password_hash" => $passwordHash
]);
?>
Dalam aplikasi produksi, tangani email duplikat dan error database tanpa membocorkan detail internal.
4. Form Login
<form method="post" action="login.php">
<label>
Email
<input
type="email"
name="email"
autocomplete="email"
required
>
</label>
<label>
Password
<input
type="password"
name="password"
autocomplete="current-password"
required
>
</label>
<button type="submit">Login</button>
</form>
5. Memproses Login
<?php
session_start();
require __DIR__ . "/config/database.php";
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
http_response_code(405);
exit;
}
$email = trim($_POST["email"] ?? "");
$password = $_POST["password"] ?? "";
$stmt = $pdo->prepare(
"SELECT id, name, email, password_hash
FROM users
WHERE email = :email
LIMIT 1"
);
$stmt->execute([
"email" => $email
]);
$user = $stmt->fetch();
if (
!$user ||
!password_verify(
$password,
$user["password_hash"]
)
) {
exit("Email atau password salah.");
}
session_regenerate_id(true);
$_SESSION["user_id"] = (int) $user["id"];
$_SESSION["user_name"] = $user["name"];
header("Location: dashboard.php");
exit;
?>
Mengapa Pesan Error Dibuat Umum?
Pesan seperti:
Email atau password salah.
lebih baik daripada memberitahu apakah email tertentu terdaftar. Ini membantu mengurangi informasi yang dapat digunakan untuk enumerasi akun.
6. Melindungi Dashboard
<?php
session_start();
if (!isset($_SESSION["user_id"])) {
header("Location: login-form.php");
exit;
}
?>
<h1>Dashboard</h1>
Pengecekan autentikasi sebaiknya dibuat reusable agar tidak ditulis ulang secara berbeda di banyak halaman.
7. Logout dengan POST
Logout mengubah state session. Gunakan request POST dan, untuk aplikasi yang lebih serius, sertakan token CSRF.
<form method="post" action="logout.php">
<button type="submit">Logout</button>
</form>
logout.php:
<?php
session_start();
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
http_response_code(405);
exit;
}
$_SESSION = [];
if (ini_get("session.use_cookies")) {
$params = session_get_cookie_params();
setcookie(
session_name(),
"",
time() - 42000,
$params["path"],
$params["domain"],
$params["secure"],
$params["httponly"]
);
}
session_destroy();
header("Location: login-form.php");
exit;
?>
Session Cookie
Pada website HTTPS, konfigurasi session cookie sebaiknya menggunakan pengaturan keamanan yang sesuai, seperti Secure, HttpOnly, dan kebijakan SameSite yang cocok dengan alur aplikasi.
Detail pengaturan dapat berbeda tergantung arsitektur aplikasi.
CSRF Token Dasar
Contoh membuat token:
<?php
session_start();
if (empty($_SESSION["csrf_token"])) {
$_SESSION["csrf_token"] = bin2hex(
random_bytes(32)
);
}
?>
Masukkan ke form:
<input
type="hidden"
name="csrf_token"
value="<?= htmlspecialchars(
$_SESSION["csrf_token"],
ENT_QUOTES,
"UTF-8"
) ?>"
>
Verifikasi:
if (
!isset($_POST["csrf_token"]) ||
!hash_equals(
$_SESSION["csrf_token"],
$_POST["csrf_token"]
)
) {
http_response_code(403);
exit("Request tidak valid.");
}
Rate Limiting
Login sebaiknya tidak dapat dicoba tanpa batas. Sistem produksi perlu mempertimbangkan rate limiting, delay adaptif, atau mekanisme perlindungan lain terhadap percobaan otomatis.
Jangan hanya mengandalkan CAPTCHA sebagai satu-satunya kontrol keamanan.
Password yang Baik
Jangan membatasi password hanya karena ingin mudah divalidasi. Dukung password yang panjang dan hindari aturan yang justru mendorong pola mudah ditebak.
Untuk aplikasi nyata, pertimbangkan kebijakan password, reset password, verifikasi email, dan autentikasi tambahan sesuai risiko.
Jangan Membuat Hash Sendiri
Hindari membuat sistem password menggunakan MD5, SHA-1, atau hash umum secara langsung.
Gunakan API password hashing yang disediakan PHP:
password_hash()
password_verify()
Prepared Statement Tetap Wajib
Password hashing tidak melindungi query SQL.
Query login tetap harus menggunakan parameter:
$stmt = $pdo->prepare(
"SELECT id, password_hash
FROM users
WHERE email = :email"
);
Jangan Simpan Data Sensitif di Session Tanpa Kebutuhan
Simpan data minimum yang diperlukan, misalnya ID pengguna dan informasi non-sensitif yang dibutuhkan aplikasi.
Jangan memasukkan password ke session.
HTTPS Penting
Password yang sudah di-hash di database tetap dikirim pengguna ke server saat login. Karena itu website login harus menggunakan HTTPS agar komunikasi jaringan terenkripsi.
Checklist Login PHP
- Password menggunakan
password_hash(). - Verifikasi menggunakan
password_verify(). - Query menggunakan PDO prepared statement.
- Session ID diregenerasi setelah login.
- Logout menggunakan mekanisme yang benar.
- HTTPS aktif.
- CSRF protection dipasang pada aksi yang relevan.
- Rate limiting dipertimbangkan.
- Error tidak membocorkan detail akun.
Kesimpulan
Sistem login bukan hanya form email dan password. Keamanan autentikasi bergantung pada beberapa lapisan: penyimpanan password yang tepat, query yang aman, session management, HTTPS, CSRF protection, dan pembatasan percobaan login.
Dengan menyelesaikan artikel ini, cluster dasar PHP & MySQL selesai. Berikutnya kita masuk ke Git & GitHub.
Artikel berikutnya untuk kamu
Belum ada rekomendasi lain.
Artikel berikutnya
Cara Membuat CRUD PHP MySQL untuk Pemula →