Tổng quan
Basic Authentication là phương thức xác thực đơn giản nhất trong HTTP, được định nghĩa trong RFC 7617. Client gửi username và password được encode Base64 trong header Authorization của mỗi HTTP request.
Đây là điểm khởi đầu tốt để hiểu các cơ chế xác thực — vì các phương pháp hiện đại hơn (Digest, JWT, OAuth2...) đều ra đời để khắc phục những hạn chế của Basic Auth.
Flow xác thực
sequenceDiagram
participant Client
participant Server
Client->>Server: GET /resource
Server-->>Client: 401 Unauthorized (WWW-Authenticate: Basic)
Client->>Client: Encode Base64(username:password)
Client->>Server: GET /resource (Authorization: Basic dXNlcjpwYXNz)
Server->>Server: Decode Base64 → Verify credentials
alt Credentials hợp lệ
Server-->>Client: 200 OK + Resource
else Credentials không hợp lệ
Server-->>Client: 401 Unauthorized
end
⚠️ Base64 KHÔNG phải mã hóa
Đây là điểm hay bị hiểu nhầm nhất. Base64 chỉ là encoding (chuyển đổi định dạng), không phải encryption.
Ví dụ, chuỗi user:password123 sau khi encode Base64 thành:
dXNlcjpwYXNzd29yZDEyMw==
Bất kỳ ai cũng có thể decode ngay lập tức:
# Decode dễ dàng trên terminal
echo "dXNlcjpwYXNzd29yZDEyMw==" | base64 --decode
# Output: user:password123
Kết luận: Nếu không có HTTPS, credentials bị lộ hoàn toàn khi bị sniff trên network.
Ví dụ thực tế
cURL:
# Cách 1: dùng flag -u
curl -u username:password https://api.example.com/resource
# Cách 2: gửi header thủ công
curl -H "Authorization: Basic dXNlcjpwYXNz" https://api.example.com/resource
# Cách 3: nhúng credentials trực tiếp vào URL
curl https://username:password@api.example.com/resource
# Lưu ý: nếu password có ký tự đặc biệt, phải percent-encode
# Ví dụ password là p@ssw0rd → encode @ thành %40
curl https://username:p%40ssw0rd@api.example.com/resource
Tương tự với các ký tự đặc biệt khác trong URL:
| Ký tự | Encode |
|---|---|
@ |
%40 |
: |
%3A |
/ |
%2F |
# |
%23 |
? |
%3F |
& |
%26 |
+ |
%2B |
% |
%25 |
PHP (Laravel):
// Middleware kiểm tra Basic Auth
public function handle(Request $request, Closure $next)
{
$credentials = base64_decode($request->header('Authorization'));
[$username, $password] = explode(':', $credentials, 2);
if (!Auth::attempt(compact('username', 'password'))) {
return response('Unauthorized', 401)
->header('WWW-Authenticate', 'Basic realm="API"');
}
return $next($request);
}
JavaScript (Fetch API):
const credentials = btoa('username:password');
fetch('https://api.example.com/resource', {
headers: {
'Authorization': `Basic ${credentials}`
}
});
Ưu & Nhược điểm
| ✅ Ưu điểm | ❌ Nhược điểm |
|---|---|
| Cực kỳ đơn giản, mọi HTTP client đều hỗ trợ | Credentials bị lộ nếu không dùng HTTPS |
| Không cần session, token hay state | Gửi credentials trong mỗi request → rủi ro cao |
| Dễ test và debug API | Không có cơ chế logout (phía server) |
| Được hỗ trợ native bởi trình duyệt | Không hỗ trợ fine-grained permissions |
Khi nào nên và không nên dùng?
✅ Phù hợp khi:
- Internal APIs trong mạng nội bộ (intranet) với HTTPS
- Script tự động hóa (CI/CD, cron jobs) cần xác thực đơn giản
- Bảo vệ môi trường STG/UAT không cho public truy cập — cấu hình ở tầng Nginx, không cần code trong app
- Kết hợp với TLS mutual authentication
Config Nginx cho môi trường STG
Use case phổ biến nhất của Basic Auth thực tế: chặn truy cập STG bằng Nginx mà không cần sửa code ứng dụng.
Bước 1 — Tạo file .htpasswd:
# Cài htpasswd
sudo apt install apache2-utils # Ubuntu/Debian
sudo yum install httpd-tools # CentOS/RHEL
# Tạo file và thêm user đầu tiên
sudo htpasswd -c /etc/nginx/.htpasswd stguser
# Thêm user tiếp theo (bỏ -c để không ghi đè)
sudo htpasswd /etc/nginx/.htpasswd anotheruser
File .htpasswd sau khi tạo (password đã được hash):
stguser:$apr1$xyz$hashedpassword
anotheruser:$apr1$abc$anotherhash
Bước 2 — Config Nginx:
server {
listen 443 ssl;
server_name stg.example.com;
# Bảo vệ toàn bộ site
auth_basic "Staging Environment";
auth_basic_user_file /etc/nginx/.htpasswd;
# Ngoại lệ: webhook endpoint không cần Basic Auth
# (vì Stripe/service bên ngoài không tự gửi credentials)
location /stripe/webhook {
auth_basic off;
proxy_pass http://127.0.0.1:8000;
}
location / {
proxy_pass http://127.0.0.1:8000;
}
}
Bước 3 — Reload Nginx:
sudo nginx -t # Kiểm tra config hợp lệ
sudo systemctl reload nginx
❌ Không phù hợp khi:
- Public API cho người dùng cuối
- Ứng dụng cần logout hoặc revoke quyền truy cập
- Hệ thống yêu cầu bảo mật cao (ngân hàng, y tế...)
- Cần phân quyền chi tiết (role-based access)
Lưu ý quan trọng
- Bắt buộc dùng HTTPS — không có ngoại lệ nào cho production
- Base64 không phải mã hóa, chỉ là encoding → dễ dàng decode
- Mỗi request đều phải gửi lại credentials
- Cân nhắc dùng API Key hoặc JWT nếu cần bảo mật tốt hơn
Tiếp theo: Digest Authentication — phiên bản cải tiến của Basic Auth, dùng hash thay vì gửi credentials dạng plaintext.