🔐 Bảo mật mật khẩu người dùng
Trong website thực tế, việc lưu mật khẩu là một vấn đề cực kỳ quan trọng.
❌ Sai lầm:
$password = "123456";
Lưu trực tiếp mật khẩu vào database.
Nếu database bị lộ → toàn bộ tài khoản bị lộ.
✅ Đúng cách:
PHP cung cấp cơ chế Hash Password để mã hóa một chiều.
Ví dụ:
Mật khẩu:
123456
Sau khi hash:
$2y$10$kL7x9a8Fj2....
Người khác không thể lấy lại mật khẩu gốc.
1️⃣ Hash mật khẩu bằng password_hash()
Cú pháp:
password_hash($password, $algorithm);
Ví dụ:
<?php
$password = "123456";
$hash = password_hash(
$password,
PASSWORD_DEFAULT
);
echo $hash;
?>
Kết quả:
$2y$10$....
Mỗi lần chạy sẽ tạo hash khác nhau.
Ví dụ:
Lần 1:
$2y$10$abc123...
Lần 2:
$2y$10$xyz789...
Nhưng PHP vẫn kiểm tra được.
2️⃣ Lưu mật khẩu vào MySQL
Ví dụ bảng users:
| id | username | password |
|---|---|---|
| 1 | admin | $2y$10$abc... |
Không lưu:
123456
Mà lưu:
$2y$10$abc123....
3️⃣ Kiểm tra mật khẩu với password_verify()
Khi đăng nhập:
Người dùng nhập:
123456
Database chứa:
$2y$10$abc123....
PHP kiểm tra:
<?php
$password_input = "123456";
$password_db = "$2y$10$abc123";
if(
password_verify(
$password_input,
$password_db
)
){
echo "Đăng nhập thành công";
}else{
echo "Sai mật khẩu";
}
?>
Kết quả:
Đăng nhập thành công
4️⃣ Ví dụ Form đăng ký đơn giản
register.php
<?php
$username = $_POST['username'];
$password = $_POST['password'];
$password_hash = password_hash(
$password,
PASSWORD_DEFAULT
);
echo $password_hash;
?>
Người dùng nhập:
username:
admin
password:
123456
PHP tạo:
$2y$10$....
5️⃣ Vì sao không dùng md5()?
Ngày xưa:
md5("123456");
Cho ra:
e10adc3949ba59abbe56e057f20f883e
Nhược điểm:
❌ Có thể bị dò bằng rainbow table
❌ Không có salt mạnh
❌ Không phù hợp cho mật khẩu hiện nay
PHP 8.2 khuyến nghị:
password_hash()
6️⃣ PASSWORD_DEFAULT là gì?
PASSWORD_DEFAULT
PHP tự chọn thuật toán mạnh nhất hiện tại.
Ưu điểm:
✅ Không cần nhớ thuật toán
✅ PHP tự nâng cấp bảo mật
✅ Code lâu dài
7️⃣ Kiểm tra hash hiện tại
PHP có:
password_needs_rehash()
Ví dụ:
if(
password_needs_rehash(
$password_hash,
PASSWORD_DEFAULT
)
){
echo "Cần tạo hash mới";
}
Dùng khi hệ thống nâng cấp bảo mật.
8️⃣ Quy trình đăng nhập thực tế
Đăng ký
|
|
Nhập password
|
|
password_hash()
|
|
Lưu MySQL
----------------
Đăng nhập
Nhập password
|
password_verify()
|
Đúng → tạo session
Sai → báo lỗi
🎯 Bài tập thực hành
Tạo hệ thống:
📌 register.php
Nhập username
Nhập password
Hash password
Lưu MySQL
📌 login.php
Nhập username
Nhập password
Kiểm tra password_verify()
Tạo session
🔐Ví dụ register full
<?php
//register.php
require_once("config.php");
if (isset($_POST['btnsubmit'])) {
$username = trim($_POST['username']);
$password = $_POST['password'];
$hoten = trim($_POST['hoten']);
$tuoi = (int)$_POST['tuoi'];
// Tạo mật khẩu đã mã hóa
$password_hash = password_hash(
$password,
PASSWORD_DEFAULT
);
// Chuẩn bị câu lệnh SQL
$sql = "
INSERT INTO users(username, password, hoten, tuoi)
VALUES (?, ?, ?, ?)
";
$stmt = mysqli_prepare($conn, $sql);
mysqli_stmt_bind_param(
$stmt,
"sssi",
$username,
$password_hash,
$hoten,
$tuoi
);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
header("Location: login.php");
exit;
}
?>
<form action="" method="post">
Nhập user name:
<input type="text" name="username" required>
<br><br>
Nhập mật khẩu:
<input type="password" name="password" required>
<br><br>
Nhập họ tên:
<input type="text" name="hoten" required>
<br><br>
Nhập tuổi:
<input type="number" name="tuoi" min="1" max="120" required>
<br><br>
<button type="submit" name="btnsubmit">
Đăng ký
</button>
</form>🎯Mô hình đăng nhập full
✅ Prepared Statement
✅
password_verify()✅
password_needs_rehash()✅
session_regenerate_id(true)✅ Tạo Session
✅ Chuyển sang
dashboard.php✅
exit;sauheader()
📄 login.php
<?php
/*
===========================================
login.php
===========================================
- Đăng nhập
- password_verify()
- Session
- Session Fixation Protection
*/
session_start();
require_once "config.php";
$message = "";
if (isset($_POST["btnLogin"])) {
$username = trim($_POST["username"]);
$password = $_POST["password"];
$sql = "
SELECT *
FROM users
WHERE username = ?
LIMIT 1
";
$stmt = mysqli_prepare($conn, $sql);
mysqli_stmt_bind_param(
$stmt,
"s",
$username
);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
//dùng SELECT WHERE lấy đúng username
if (mysqli_num_rows($result) == 0) {
$message = "❌ Username không tồn tại.";
} else {
$user = mysqli_fetch_assoc($result);
//so sánh password của username đó
if (
password_verify(
$password,
$user["password"]
)
) {
// Hash cũ?
if (
password_needs_rehash(
$user["password"],
PASSWORD_DEFAULT
)
) {
$newHash = password_hash(
$password,
PASSWORD_DEFAULT
);
$sqlUpdate = "
UPDATE users
SET password=?
WHERE id=?
";
$stmtUpdate = mysqli_prepare(
$conn,
$sqlUpdate
);
mysqli_stmt_bind_param(
$stmtUpdate,
"si",
$newHash,
$user["id"]
);
mysqli_stmt_execute($stmtUpdate);
}
// Chống Session Fixation
session_regenerate_id(true);
$_SESSION["user_id"] = $user["id"];
$_SESSION["username"] = $user["username"];
header("Location: dashboard.php");
exit;
} else {
$message = "❌ Sai mật khẩu.";
}
}
}
?>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Login</title>
</head>
<body>
<h2>Đăng nhập</h2>
<?php
if ($message != "") {
echo "<p>$message</p>";
}
?>
<form method="post">
Username
<br>
<input
type="text"
name="username"
required
>
<br><br>
Password
<br>
<input
type="password"
name="password"
required
>
<br><br>
<button
type="submit"
name="btnLogin"
>
Đăng nhập
</button>
</form>
</body>
</html>
📄 dashboard.php
<?php
session_start();
if (!isset($_SESSION["user_id"])) {
header("Location: login.php");
exit;
}
?>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Dashboard</title>
</head>
<body>
<h1>Dashboard</h1>
Xin chào
<strong>
<?= htmlspecialchars($_SESSION["username"]) ?>
</strong>
<br><br>
<a href="logout.php">
Đăng xuất
</a>
</body>
</html>
📄 logout.php
<?php
session_start();
// Xóa toàn bộ session
$_SESSION = [];
// Hủy session
session_destroy();
// Quay về trang login
header("Location: login.php");
exit;
📂 Cấu trúc thư mục
project/
│ config.php
│ login.php
│ dashboard.php
│ logout.php
└── users
Đây cũng chính là mô hình đăng nhập cơ bản mà hầu hết các framework PHP (như Laravel, CodeIgniter, Symfony) đều triển khai với các bước:
Nhập username/password.
Truy vấn người dùng theo username.
password_verify()để kiểm tra mật khẩu.session_regenerate_id(true)để tăng cường bảo mật.Lưu thông tin cần thiết vào
$_SESSION.Chuyển hướng đến trang được bảo vệ.
Kiểm tra
$_SESSIONở mọi trang cần đăng nhập.logout.phpxóa session và quay lại trang đăng nhập.
✅ Sau bài 30 bạn hiểu:
✔ Vì sao không lưu mật khẩu dạng text
✔ password_hash()
✔ password_verify()
✔ Bảo mật đăng nhập cơ bản
✔ Chuẩn bị xây dựng hệ thống user thực tế
📚 Bài tiếp theo:
🐘 Bài 31 — Filter dữ liệu trong PHP
(kiểm tra, làm sạch dữ liệu trước khi lưu database)
x1





Không có nhận xét nào:
Đăng nhận xét