Giới thiệu
Trong thời đại công nghệ số hiện nay, các nhà phát triển web không chỉ tạo ra những giao diện người dùng đẹp mắt mà còn phải bảo vệ dữ liệu của người dùng khỏi các cuộc tấn công của tin tặc và các bài kiểm tra xâm nhập. Một ứng dụng nếu không được xây dựng với các biện pháp bảo mật phù hợp thì sẽ dễ dàng bị các công cụ như OWASP ZAP can thiệp vào, từ đó tiết lộ thông tin nhạy cảm như tên người dùng và mật khẩu.
Vậy, làm thế nào để các nhà phát triển đảm bảo rằng ngay cả khi ZAP ở giữa, nó cũng không thể nhìn thấy thông tin đăng nhập dưới dạng văn bản thuần?
Hãy cùng tìm hiểu nhé.
Bảo vệ Backend: Mã hóa với bcrypt (hoặc argon2)
Mật khẩu không bao giờ nên được lưu trữ dưới dạng văn bản thuần trên backend. Thay vào đó, các nhà phát triển nên sử dụng thư viện mã hóa, ví dụ:
- bcrypt (sử dụng bcryptjs trong Node.js)
- argon2 (có thể sử dụng với gói npm argon2 và cung cấp bảo vệ mạnh mẽ hơn chống lại các cuộc tấn công GPU)
Ví dụ (Node.js API):
javascript
import bcrypt from 'bcryptjs';
const saltRounds = 12;
// Mã hóa trước khi lưu trữ
const hashedPassword = await bcrypt.hash('user-password', saltRounds);
// Kiểm tra đăng nhập sau đó
const isMatch = await bcrypt.compare('user-password', hashedPassword);
console.log(isMatch ? 'Mật khẩu hợp lệ' : 'Đăng nhập không hợp lệ');
Lưu ý quan trọng: Mã hóa này chỉ chạy trên API backend, không bao giờ ở phía frontend (React).
Bảo vệ Giao thức: Ẩn thông tin đăng nhập khỏi ZAP
Ngay cả khi bạn đã mã hóa trên backend, nếu bạn truyền mật khẩu dưới dạng văn bản thuần qua HTTP, ZAP vẫn có thể nhìn thấy chúng. Để ngăn chặn điều này, các nhà phát triển cần cấu hình lớp giao thức.
1. Không phục vụ qua HTTP (Sử dụng HTTPS mọi lúc)
Luôn phục vụ trang web của bạn qua TLS/SSL. Giao thức này mã hóa lưu lượng giữa client và server, vì vậy ZAP (không có việc chèn chứng chỉ) sẽ không bao giờ nhìn thấy thông tin đăng nhập của bạn.
Thư viện/Công cụ:
- helmet (một middleware express để thêm tiêu đề bảo mật)
- SSL miễn phí sử dụng Let’s Encrypt
2. Xác thực dựa trên Token (JWT, OAuth2)
Thay vì lặp lại tên người dùng và mật khẩu, hãy cấp phát một token sau khi đăng nhập.
- Đầu tiên khi đăng nhập: người dùng gửi thông tin đăng nhập một lần (qua HTTPS).
- Server cấp phát một JWT (JSON Web Token).
- Đối với mỗi yêu cầu tiếp theo, client sẽ chỉ gửi token.
Thư viện/Công cụ:
- jsonwebtoken (Node.js)
- passport-jwt cho Express/NestJS.
3. Mã hóa phía client (tùy chọn cho các ứng dụng bảo mật cao hơn)
Một số ứng dụng bảo mật cao (như ngân hàng) sẽ mã hóa mật khẩu ở phía frontend trước khi gửi đi.
- Frontend mã hóa mật khẩu bằng khóa công khai RSA.
- Backend giải mã bằng khóa riêng RSA và sau đó mã hóa bằng bcrypt.
- ZAP sẽ chỉ nhìn thấy một blob đã được mã hóa.
Thư viện/Công cụ:
- node-forge (mã hóa RSA trong JS)
- crypto (tích hợp sẵn trong Node.js).
4. Xác thực không mật khẩu (Không có mật khẩu trong quá trình truyền)
Các ứng dụng gần đây không cần mật khẩu với WebAuthn / FIDO2.
Thay vì gửi thông tin đăng nhập tới trình duyệt, ứng dụng sẽ tạo ra một bằng chứng mã hóa.
Không có gì nhạy cảm nào được truyền qua mạng.
Thư viện/Công cụ:
- @simplewebauthn/browser + @simplewebauthn/server
- Hỗ trợ đăng nhập sinh trắc học, khóa bảo mật (YubiKey), v.v.
Tóm tắt Quy trình Đăng Nhập An Toàn
- Frontend (React) → Người dùng nhập thông tin đăng nhập → Gửi qua HTTPS.
- Backend (Node.js API) → Mã hóa bất đồng bộ mật khẩu bằng bcrypt/argon2 trước khi lưu trữ.
- Token hóa → Trả về một JWT thay vì tiết lộ mật khẩu một lần nữa.
- Tăng cường tùy chọn → Thêm mã hóa phía client (RSA) hoặc không cần mật khẩu (WebAuthn).
Góc Nhìn của Tester (qua ZAP)
- Không an toàn: ZAP nhìn thấy username=alice&password=12345.
- An toàn với HTTPS + JWT: ZAP nhìn thấy yêu cầu đã được mã hóa với token, không có mật khẩu văn bản thuần nào.
- Tương tự với WebAuthn: ZAP nhìn thấy bằng chứng mã hóa... không bao giờ thấy thông tin xác thực.
Kết luận
- Phát triển web + Bảo mật mạng = Suy nghĩ ngoài giao diện người dùng.
- Sử dụng bcrypt/argon2 ở backend.
- Sử dụng HTTPS.
- Sử dụng token thay vì mật khẩu.
- Sử dụng WebAuthn/FIDO2 để bảo mật trong tương lai.
Chỉ cần như vậy, ngay cả khi ZAP ở giữa, bí mật vẫn an toàn cho người dùng của bạn.