Menyimpan password pengguna dengan cara yang benar adalah salah satu aspek keamanan paling kritis dalam pengembangan web. Banyak developer pemula menyimpan password dalam bentuk teks biasa atau menggunakan fungsi hash lama seperti MD5 dan SHA1 yang sudah tidak aman. PHP menyediakan fungsi bawaan password_hash() dan password_verify() yang dirancang khusus untuk keperluan ini dan sangat mudah digunakan.
Mengapa MD5 dan SHA1 Tidak Aman untuk Password?
MD5 dan SHA1 adalah fungsi hash kriptografi umum yang dirancang untuk kecepatan. Untuk password, ini justru berbahaya karena:
- Terlalu cepat โ attacker bisa mencoba miliaran kombinasi per detik (brute force).
- Deterministic tanpa salt โ hash yang sama untuk password yang sama, rentan terhadap rainbow table attack.
- Sudah dianggap lemah secara kriptografi.
Fungsi password_hash() menggunakan algoritma seperti Bcrypt secara default yang sengaja dirancang lambat dan secara otomatis menambahkan salt unik.
Menggunakan password_hash()
Penggunaan password_hash() sangat sederhana:
<?php
$password_asli = "RahasiaKu123!";
// Membuat hash password dengan algoritma bcrypt (default)
$hash = password_hash($password_asli, PASSWORD_DEFAULT);
echo $hash;
// Contoh output: $2y$10$abcdefghijklmnopqrstu.hashedpasswordstring
// Hash baru setiap kali dipanggil meski password sama!
Beberapa hal penting tentang password_hash():
PASSWORD_DEFAULTโ menggunakan algoritma terbaik yang tersedia di versi PHP saat ini (bcrypt di PHP 8).- Hash yang dihasilkan selalu berbeda meskipun passwordnya sama, karena salt di-generate acak setiap kali.
- Simpan hasil hash di kolom database dengan tipe
VARCHAR(255)untuk mengakomodasi perubahan panjang di masa depan.
Memverifikasi Password dengan password_verify()
Untuk mengecek apakah password yang dimasukkan pengguna cocok dengan hash yang tersimpan:
<?php
$hash_dari_database = '$2y$10$abcdefghijklmnopqrstu.hashedpasswordstring';
$password_input = "RahasiaKu123!";
$password_salah = "passwordlain";
if (password_verify($password_input, $hash_dari_database)) {
echo "Password benar! Login berhasil.";
} else {
echo "Password salah!";
}
// password_verify() aman dari timing attack
// karena selalu membutuhkan waktu yang sama untuk perbandingan
Jangan membandingkan hash secara manual dengan operator == atau ===. Selalu gunakan password_verify() yang dirancang aman dari timing attack.
Implementasi Lengkap: Registrasi dan Login
Berikut implementasi registrasi pengguna yang menyimpan password dengan aman:
<?php
// register.php
require 'koneksi.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = trim($_POST['username']);
$email = trim($_POST['email']);
$password = $_POST['password'];
$konfirm = $_POST['konfirm_password'];
// Validasi dasar
if (strlen($password) < 8) {
$error = "Password minimal 8 karakter.";
} elseif ($password !== $konfirm) {
$error = "Password dan konfirmasi tidak cocok.";
} else {
// Hash password sebelum disimpan
$hash = password_hash($password, PASSWORD_DEFAULT);
$stmt = $pdo->prepare(
"INSERT INTO users (username, email, password) VALUES (:u, :e, :p)"
);
try {
$stmt->execute([':u' => $username, ':e' => $email, ':p' => $hash]);
$sukses = "Registrasi berhasil! Silakan login.";
} catch (PDOException $e) {
$error = "Username atau email sudah digunakan.";
}
}
}
Dan proses login yang memverifikasi password:
<?php
// login.php
session_start();
require 'koneksi.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = trim($_POST['username']);
$password = $_POST['password'];
$stmt = $pdo->prepare("SELECT id, username, password FROM users WHERE username = :u LIMIT 1");
$stmt->execute([':u' => $username]);
$user = $stmt->fetch();
// Verifikasi: cek user ada DAN password cocok
if ($user && password_verify($password, $user['password'])) {
// Cek apakah hash perlu di-upgrade ke algoritma baru
if (password_needs_rehash($user['password'], PASSWORD_DEFAULT)) {
$hash_baru = password_hash($password, PASSWORD_DEFAULT);
$update = $pdo->prepare("UPDATE users SET password = :p WHERE id = :id");
$update->execute([':p' => $hash_baru, ':id' => $user['id']]);
}
session_regenerate_id(true);
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
header('Location: dashboard.php');
exit;
} else {
$error = "Username atau password salah.";
}
}
Fungsi password_needs_rehash()
Fungsi ini sangat berguna saat kamu memperbarui algoritma atau cost factor. Saat pengguna login berhasil, cek apakah hashnya perlu diperbarui dan simpan yang baru secara otomatis โ tanpa perlu meminta pengguna ganti password.
Mengatur Cost Factor Bcrypt
Cost factor menentukan seberapa lambat proses hashing. Semakin tinggi nilainya, semakin aman tapi semakin lambat. Default adalah 10; nilai 12 sudah cukup baik untuk kebanyakan aplikasi:
<?php
$options = ['cost' => 12];
$hash = password_hash($password, PASSWORD_BCRYPT, $options);
Kesimpulan
Mengamankan password di PHP sangat mudah dengan password_hash() dan password_verify(). Tidak ada alasan untuk menggunakan MD5, SHA1, atau menyimpan password dalam bentuk teks biasa. Selalu hash password sebelum disimpan ke database, verifikasi dengan password_verify(), dan manfaatkan password_needs_rehash() untuk menjaga hash tetap mutakhir.