Bỏ qua tới nội dung

HTTP Basic Authentication

Trình duyệt và server trao đổi tài khoản, mật khẩu qua header Authorization như thế nào, và vì sao bắt buộc phải có HTTPS.

Sơ đồ tương tác — phóng to, thu nhỏ hoặc xuất ảnh bằng thanh công cụ của sơ đồ. Mở toàn màn hình

Basic Auth là gì

HTTP Basic Authentication (đặc tả trong RFC 7617) là cách xác thực đơn giản nhất của HTTP: trình duyệt gửi kèm tên đăng nhập và mật khẩu trong header Authorization của mọi request.

Không có form đăng nhập, không có session, không có cookie. Server không nhớ ai đã đăng nhập: mỗi request đến, nó đọc header, kiểm tra lại tài khoản từ đầu rồi mới trả lời. Vì thế Basic Auth là cơ chế stateless.

Cách hoạt động

Sơ đồ phía trên chia làm ba đoạn.

1. Request đầu tiên bị từ chối

Trình duyệt chưa biết trang cần đăng nhập nên gửi request bình thường. Server trả 401 Unauthorized kèm header WWW-Authenticate cho biết kiểu xác thực và realm (tên vùng cần bảo vệ):

GET /admin HTTP/1.1
Host: example.com

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="Admin", charset="UTF-8"

Thấy Basic trong WWW-Authenticate, trình duyệt hiện hộp thoại hỏi tên đăng nhập và mật khẩu. Hộp thoại này do trình duyệt vẽ, trang web không tuỳ biến được.

2. Gửi tài khoản

Người dùng nhập toby / secret. Trình duyệt ghép thành toby:secret, mã hoá Base64 thành dG9ieTpzZWNyZXQ=, rồi gửi lại đúng request đó kèm header:

GET /admin HTTP/1.1
Host: example.com
Authorization: Basic dG9ieTpzZWNyZXQ=

Server decode Base64, tách theo dấu : đầu tiên, so khớp với kho tài khoản (file htpasswd, bảng users…). Đúng thì trả 200 OK. Sai thì lại trả 401, trình duyệt hiện lại hộp thoại.

3. Các request tiếp theo

Trình duyệt tự gửi lại header Authorization cho mọi request tới cùng realm, người dùng không phải nhập lại. Server vẫn kiểm tra lại tài khoản ở từng request.

Header Authorization được tạo thế nào

Authorization: Basic base64( username + ":" + password )

Bạn có thể tự thử với công cụ Base64 Encode / Decode: nhập toby:secret, bấm Encode sẽ ra dG9ieTpzZWNyZXQ=.

Vài điểm cần nhớ:

  • Tên đăng nhập không được chứa dấu :, vì server tách ở dấu : đầu tiên. Mật khẩu thì được.
  • charset="UTF-8" trong WWW-Authenticate báo cho trình duyệt mã hoá tài khoản có dấu (tiếng Việt) bằng UTF-8. Thiếu nó, mỗi trình duyệt có thể mã hoá một kiểu.
  • Base64 chỉ là cách biểu diễn byte thành ký tự an toàn cho header, không phải mã hoá bảo mật. Ai bắt được header đều decode ra mật khẩu ngay.

Thử bằng curl

# curl tự tạo header Authorization
curl -u toby:secret https://example.com/admin

# Hoặc tự viết header
curl -H "Authorization: Basic dG9ieTpzZWNyZXQ=" https://example.com/admin

# -v để xem 401 và WWW-Authenticate khi không gửi tài khoản
curl -v https://example.com/admin

Dùng trong thực tế

nginx

Hay dùng nhất để chặn nhanh một trang staging hoặc công cụ nội bộ, không phải sửa code ứng dụng:

# Tạo file tài khoản (mật khẩu được hash, không lưu dạng rõ)
htpasswd -c /etc/nginx/.htpasswd toby
location /admin {
    auth_basic           "Admin";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

Chuỗi sau auth_basic chính là realm trong WWW-Authenticate.

Laravel

Laravel có sẵn middleware auth.basic, mặc định kiểm tra cột email + password của bảng users:

Route::get('/admin/report', ReportController::class)->middleware('auth.basic');

Middleware này đăng nhập người dùng vào session sau lần kiểm tra đầu tiên. Muốn đúng tinh thần stateless (thường dùng cho API), viết middleware riêng gọi Auth::onceBasic(): chỉ xác thực cho request hiện tại, không tạo session.

Rủi ro bảo mật

  • Bắt buộc HTTPS. Header gửi Base64 gần như là văn bản rõ. Qua HTTP thường, bất kỳ ai trên đường truyền (Wi-Fi công cộng, proxy) đều đọc được mật khẩu.
  • Gửi mật khẩu ở mọi request. Mật khẩu thật đi qua mạng liên tục, chứ không phải một token có hạn. Lộ một request là lộ mật khẩu.
  • Không có đăng xuất. Trình duyệt giữ tài khoản tới khi đóng hẳn, server không có cách bảo trình duyệt "quên" đi.
  • Không chống dò mật khẩu. Cần giới hạn số lần thử, ví dụ limit_req của nginx hoặc fail2ban.
  • Dễ bị CSRF. Trình duyệt tự đính kèm tài khoản cho mọi request tới site, kể cả request do trang khác kích hoạt. Đừng dùng Basic Auth cho các thao tác ghi dữ liệu từ trình duyệt.

Khi nào nên dùng

Nên dùng Không nên dùng
Chặn trang staging, trang demo khỏi người lạ và bot Đăng nhập cho người dùng cuối
Công cụ nội bộ ít người dùng (dashboard, phpMyAdmin) Ứng dụng cần đăng xuất, phân quyền, quên mật khẩu
API gọi giữa các server với nhau, qua HTTPS Bất cứ thứ gì chạy trên HTTP thường

So với các cách khác:

  • Session cookie: chỉ gửi mật khẩu một lần lúc đăng nhập, sau đó gửi session id. Đăng xuất được, có form riêng.
  • Bearer token / JWT: gửi token có hạn dùng thay cho mật khẩu, thu hồi hoặc hết hạn được mà không phải đổi mật khẩu.

Basic Auth thắng ở chỗ đơn giản: mọi trình duyệt, curl, thư viện HTTP đều hỗ trợ sẵn, không cần viết dòng code nào ở phía client.

Xem tất cả