PHP và MySQL Bài 16: Session trong PHP - Quản lý đăng nhập và phiên làm việc bảo mật
Sau khi đã nắm vững cách quản lý trạng thái đăng nhập bằng Session (Bài 16), câu hỏi tiếp theo cực kỳ quan trọng xuất hiện: Dữ liệu tài khoản và mật khẩu của người dùng được lưu trữ thế nào trong cơ sở dữ liệu (Database)?
Một sai lầm chí mạng của các lập trình viên mới vào nghề là lưu mật khẩu dưới dạng văn bản thuần túy (Plaintext). Ví dụ: Cột password trong Database lưu nguyên chữ secure_pass_123.
Nếu hệ thống bị tấn công SQL Injection và cơ sở dữ liệu bị rò rỉ, toàn bộ mật khẩu của người dùng sẽ rơi vào tay hacker. Tệ hơn nữa, người dùng có xu hướng dùng chung một mật khẩu cho mọi trang web (Email, Ngân hàng, Mạng xã hội), dẫn đến một thảm họa bảo mật dây chuyền.
Để giải quyết triệt để vấn đề này, chúng ta không bao giờ "mã hóa" (encrypt) mật khẩu, mà sử dụng kỹ thuật Băm mật khẩu (Password Hashing).
1. Bản chất của Băm mật khẩu (Hashing) khác gì Mã hóa (Encryption)?
Nhiều người thường nhầm lẫn giữa hai khái niệm này, nhưng về mặt kiến trúc bảo mật, chúng hoàn toàn khác nhau:
- Mã hóa (Encryption) là quá trình hai chiều: Dữ liệu được khóa lại bằng một khóa bí mật (Key) và có thể giải mã ngược lại thành văn bản gốc nếu có chìa khóa.
- Băm (Hashing) là quá trình một chiều: Dữ liệu được đưa qua một thuật toán toán học phức tạp để biến thành một chuỗi ký tự ngẫu nhiên (gọi là Hash). Tuyệt đối không thể giải mã ngược lại từ chuỗi Hash để lấy ra mật khẩu gốc.
Vậy hệ thống kiểm tra mật khẩu kiểu gì nếu không thể giải mã? Mỗi lần người dùng đăng nhập, hệ thống sẽ lấy mật khẩu họ vừa gõ, băm nó theo đúng thuật toán đó, và so sánh chuỗi kết quả với chuỗi Hash đang được lưu trong Database. Nếu hai chuỗi khớp nhau, nghĩa là mật khẩu chính xác!
2. Các phương pháp lỗi thời (Tuyệt đối không dùng)
Trong quá khứ, người ta thường dùng các hàm toán học cũ như md5() hoặc sha1() để băm mật khẩu.
// ❌ CÁCH LÀM CŨ KỸ VÀ KÉM AN TOÀN
$matKhauGoc = "secure_pass_123";
$chuoiMaHash = md5($matKhauGoc);
// Kết quả: e10adc3949ba59abbe56e057f20f883e (Luôn cố định cho một chuỗi)
Tại sao chúng đã lỗi thời?
Với sự phát triển của phần cứng hiện đại và các bảng mã dựng sẵn (Rainbow Tables), hacker có thể dùng GPU để đoán hàng tỷ chuỗi md5 mỗi giây. Chỉ mất vài giây để hacker dịch ngược lại các mật khẩu đơn giản từ chuỗi MD5.
3. Tiêu chuẩn hiện đại: password_hash() và password_verify()
PHP cung cấp sẵn một thư viện băm mật khẩu cực kỳ mạnh mẽ, hiện đại và đạt chuẩn quốc gia từ phiên bản 5.5 trở lên. Trái tim của nó gồm hai hàm chính:
A. Hàm password_hash() - Tạo chuỗi băm an toàn
Hàm này sử dụng các thuật toán mạnh nhất hiện nay (như Bcrypt hoặc Argon2). Điểm đặc biệt là nó tự động tích hợp cơ chế Salt (chuỗi ngẫu nhiên nối vào mật khẩu trước khi băm) để chống lại kiểu tấn công dò bảng mã.
Cú pháp:
$hash = password_hash($password, PASSWORD_DEFAULT);
(Lưu ý: PASSWORD_DEFAULT chỉ định PHP sử dụng thuật toán mạnh nhất hiện tại của hệ thống, thường tạo ra một chuỗi dài 60 ký tự. Vì vậy, cột password trong Database của bạn phải được thiết lập kiểu dữ liệu là VARCHAR(255)).
Ví dụ thực tế khi đăng ký tài khoản:
<?php
$matKhauThucTe = "MatKhauCucKyBaoMat@123";
// Tiến hành băm mật khẩu trước khi lưu vào Database
$matKhauDaBam = password_hash($matKhauThucTe, PASSWORD_DEFAULT);
echo "Chuỗi lưu trong Database: " . $matKhauDaBam;
// Kết quả sẽ trông giống như: $2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi
?>
B. Hàm password_verify() - Kiểm tra đăng nhập
Khi người dùng gõ mật khẩu để đăng nhập, bạn không tự băm rồi so sánh chuỗi thủ công, mà hãy dùng password_verify(). Hàm này cực kỳ thông minh: nó tự động tách chuỗi Salt từ Database ra để kiểm tra.
Ví dụ thực tế khi xử lý đăng nhập:
<?php
session_start();
$nhapTuBanPhim = "MatKhauCucKyBaoMat@123"; // Mật khẩu user vừa gõ ở form login
// Giả sử ta lấy được chuỗi hash từ Database lên ứng với tài khoản này
$chuoiHashTuDatabase = '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi';
// Kiểm tra tính khớp nhau
if (password_verify($nhapTuBanPhim, $chuoiHashTuDatabase)) {
echo "Mật khẩu chính xác! Đăng nhập thành công.";
$_SESSION['is_logged_in'] = true;
} else {
echo "Mật khẩu không chính xác.";
}
?>
Tổng kết Bài 17 và Khép lại Phần 4
Đến đây, bạn đã hoàn thiện toàn bộ bức tranh về quản lý trạng thái và bảo mật cơ bản:
- Cookie (Bài 15): Lưu trữ dữ liệu cấu hình nhỏ ở phía trình duyệt.
- Session (Bài 16): Quản lý phiên làm việc bảo mật ở phía máy chủ bằng cơ chế két sắt và chìa khóa định danh.
- Password Hashing (Bài 17): Khóa chặt bí mật của người dùng bằng cơ chế băm một chiều an toàn tuyệt đối.
Bạn đã trang bị đầy đủ tư duy và công cụ của một Backend Developer chuyên nghiệp trong việc xây dựng hệ thống xác thực người dùng.
Ở phần tiếp theo, chúng ta sẽ bước vào giai đoạn cốt lõi nhất của lập trình Web Backend: Phần 5 - Cơ Sở Dữ Liệu & PDO (PHP Data Objects). Bài 18 sẽ mở màn bằng việc trả lời câu hỏi: Làm thế nào để kết nối ứng dụng PHP của bạn với hệ quản trị cơ sở dữ liệu MySQL một cách an toàn và chuẩn mực nhất?
All rights reserved