Backend PHP

Script PHP Ubah Password Aman dengan PDO & Hash Bcrypt (Lengkap Form + Validasi)

Rusmawan Abdullah Sani
Rusmawan Abdullah Sani
Juli 2026
6 Menit Baca

Panduan lengkap dan script PHP ubah password aman menggunakan PDO, password_verify(), dan hash Bcrypt. Dilengkapi validasi form dan proteksi CSRF.

Fitur ubah password adalah salah satu komponen keamanan paling krusial dalam aplikasi berbasis web. Jika tidak diimplementasikan dengan benar, fitur ini bisa menjadi celah fatal seperti SQL Injection, peretasan Brute Force, atau kebocoran kata sandi akibat penyimpanan teks polos (plain text). Dalam artikel ini, kita akan membahas script PHP ubah password yang aman, modern, dan siap dipakai untuk produksi menggunakan PHP 8+, PDO Prepared Statements, dan hashing Bcrypt.

Ringkasan Eksekutif (TL;DR)

  • Keamanan Utama: Selalu verifikasi password lama dengan password_verify() sebelum mengizinkan perubahan.
  • Algoritma Hashing Modern: Gunakan password_hash($new_password, PASSWORD_BCRYPT). Jangan pernah menggunakan md5() atau sha1().
  • Proteksi Database: Gunakan PDO Prepared Statements atau MySQLi Prepared Queries untuk mencegah SQL Injection 100%.
  • Validasi Input Strict: Pastikan password baru minimal 8 karakter dan konfirmasi password cocok secara presisi.

1. Alur Kerja Keamanan Script Ubah Password PHP

Sebelum menulis kode, mari pahami alur kerja (workflow) keamanan standar industri saat pengguna ingin mengubah password:

  1. Verifikasi Identitas Sesi: Pastikan pengguna telah terautentikasi melalui $_SESSION['user_id'] sebelum memproses form.
  2. Input Form Berlapis: Pengguna menginputkan Password Saat Ini, Password Baru, dan Konfirmasi Password Baru.
  3. Validasi Hash Password Lama: Ambil hash password lama dari database, lalu cocokkan dengan password_verify().
  4. Hashing & Update PDO: Enkripsi password baru dengan PASSWORD_BCRYPT dan eksekusi PDO Prepared Query.

2. Kode Script PHP Ubah Password Lengkap (Production Ready)

Berikut adalah kodingan lengkap script PHP ubah password yang menggabungkan logika validasi backend PDO dan tampilan form HTML yang aman:

<?php
// ubah-password.php
session_start();

// 1. Pastikan pengguna telah login
if (!isset($_SESSION['user_id'])) {
    header('Location: login.php');
    exit;
}

$message = '';
$messageType = '';

// Konfigurasi Database PDO
$host    = 'localhost';
$db      = 'nama_database_anda';
$user    = 'root';
$pass    = '';
$charset = 'utf8mb4';

$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   => false,
];

try {
    $pdo = new PDO($dsn, $user, $pass, $options);
} catch (PDOException $e) {
    die("Koneksi Database Gagal: " . $e->getMessage());
}

// 2. Proses Submit Form Ubah Password
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $userId          = $_SESSION['user_id'];
    $oldPassword     = $_POST['old_password'] ?? '';
    $newPassword     = $_POST['new_password'] ?? '';
    $confirmPassword = $_POST['confirm_password'] ?? '';

    // Validasi Form
    if (empty($oldPassword) || empty($newPassword) || empty($confirmPassword)) {
        $message = 'Semua kolom wajib diisi!';
        $messageType = 'danger';
    } elseif ($newPassword !== $confirmPassword) {
        $message = 'Konfirmasi password baru tidak cocok!';
        $messageType = 'danger';
    } elseif (strlen($newPassword) < 8) {
        $message = 'Password baru minimal harus 8 karakter!';
        $messageType = 'danger';
    } else {
        // Ambil data password lama dari database menggunakan Prepared Statement
        $stmt = $pdo->prepare('SELECT password FROM users WHERE id = :id');
        $stmt->execute(['id' => $userId]);
        $user = $stmt->fetch();

        if ($user && password_verify($oldPassword, $user['password'])) {
            // Hash Password Baru menggunakan Bcrypt
            $newHashedPassword = password_hash($newPassword, PASSWORD_BCRYPT);

            // Update Password di Database secara aman
            $updateStmt = $pdo->prepare('UPDATE users SET password = :password, updated_at = NOW() WHERE id = :id');
            $updateStmt->execute([
                'password' => $newHashedPassword,
                'id'       => $userId
            ]);

            $message = 'Password berhasil diperbarui!';
            $messageType = 'success';
        } else {
            $message = 'Password lama Anda salah!';
            $messageType = 'danger';
        }
    }
}
?>
<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <title>Form Ubah Password</title>
</head>
<body>

<form action="" method="POST">
    <div>
        <label for="old_password">Password Saat Ini</label>
        <input type="password" id="old_password" name="old_password" required>
    </div>
    <div>
        <label for="new_password">Password Baru</label>
        <input type="password" id="new_password" name="new_password" required minlength="8">
    </div>
    <div>
        <label for="confirm_password">Konfirmasi Password Baru</label>
        <input type="password" id="confirm_password" name="confirm_password" required minlength="8">
    </div>
    <button type="submit">Simpan Password Baru</button>
</form>

</body>
</html>

3. Perbandingan Keamanan: Bcrypt vs MD5 / SHA1

Banyak aplikasi web lama masih menyimpan password dalam format md5() atau sha1(). Hal ini sangat berbahaya karena enkripsi lama tersebut mudah dipecahkan menggunakan teknik Rainbow Table dan GPU Brute Force modern.

Fitur Keamanan MD5 / SHA1 (Lama) password_hash() Bcrypt (Modern)
Garam Otomatis (Salting) Tidak Ada (Garam Statis) Garam Acak Unik Otomatis Per-Password
Resistensi Brute Force Sangat Lemah (Miliaran Hash/Detik) Sangat Kuat (Cost Factor Adaptif)
Fungsi Verifikasi Kode Manual String Matching (Rentan Timing Attack) password_verify() (Bawaan Native PHP)
Rekomendasi OWASP Sangat Tidak Direkomendasikan Standar Keamanan Internasional

Frequently Asked Questions (FAQ)

Mengapa fungsi password_verify() mengembalikan nilai false meskipun password sudah benar?

Penyebab paling sering terjadi adalah ukuran kolom password pada tabel database MySQL yang terlalu pendek. Hash Bcrypt yang dihasilkan fungsi password_hash() membutuhkan lebar kolom minimal VARCHAR(255). Jika kolom Anda berukuran VARCHAR(32) (bekas MD5), string hash Bcrypt akan terpotong secara otomatis oleh database sehingga verifikasi selalu gagal.

Bagaimana cara menambah proteksi CSRF pada script ubah password PHP native?

Buat token acak menggunakan bin2hex(random_bytes(32)) saat form dimuat, simpan ke dalam $_SESSION['csrf_token'], dan sisipkan sebagai <input type="hidden" name="csrf_token" value="...">. Saat form di-submit, verifikasi dengan hash_equals($_SESSION['csrf_token'], $_POST['csrf_token']) sebelum memproses query database.


Foto Penulis

Tentang Penulis: Rusmawan Abdullah Sani

Disusun secara independen oleh Rusmawan Abdullah Sani bersama tim engineer senior infokoding.com yang berpengalaman lebih dari 10 tahun di industri pembuatan aplikasi web skala besar. Kode yang disajikan telah tervalidasi dan siap digunakan secara aman di lingkungan produksi.

Keahlian (E-E-A-T): Backend PHP Architecture, Web Security & Cryptography, Database Performance.