Xác thực & bảo mật
Libre WebUI sử dụng tài khoản người dùng cục bộ với phiên JWT. Bản cài mới luôn cho phép tạo một quản trị viên cục bộ ban đầu. Đăng ký công khai cho mọi tài khoản cục bộ hoặc OAuth tiếp theo mặc định bị đóng.
Thiết lập lần đầu
Khi cơ sở dữ liệu chưa có người dùng:
- Libre WebUI hiển thị quy trình thiết lập lần đầu.
- Người dùng tạo tài khoản cục bộ đầu tiên.
- Tài khoản được gán vai trò
admin. - Mọi đăng ký công khai tiếp theo vẫn bị đóng trừ khi được bật rõ ràng.
Cơ sở dữ liệu hiện có giữ nguyên người dùng và vai trò hiện tại.
Tài khoản cục bộ
Đăng ký cục bộ yêu cầu:
- Tên người dùng
- Mật khẩu từ 12 ký tự đến 72 byte UTF-8, có chữ hoa, chữ thường và chữ số
- Email tùy chọn
Mật khẩu được băm bằng bcrypt trước khi lưu. Các tuyến đăng nhập và đăng ký bị giới hạn tốc độ.
Phê duyệt đăng ký
Đăng ký công khai tự nó không cấp quyền truy cập. Mỗi tài khoản được tạo qua biểu mẫu đăng ký công khai hoặc nhà cung cấp OAuth đều bắt đầu ở trạng thái pending và phải được quản trị viên phê duyệt trước khi đăng nhập.
Ngoại lệ duy nhất là tài khoản ban đầu: tài khoản thực đầu tiên trên cơ sở dữ liệu trống được tạo nguyên tử ở trạng thái active với vai trò admin, để bản cài mới luôn có quản trị viên hoạt động. Mọi lượt đăng ký sau đều chờ xét duyệt.
Người dùng đang chờ sẽ thấy:
- Đăng ký thành công nhưng không trả token phiên. API phản hồi
202vớiapprovalRequired: true, còn UI giải thích rằng quản trị viên phải phê duyệt tài khoản. - Đăng nhập bằng mật khẩu với thông tin đúng bị từ chối bằng
403và mãACCOUNT_PENDING("Tài khoản của bạn đang chờ quản trị viên phê duyệt"). Đăng nhập OAuth chuyển hướng lại trang đăng nhập với?approval=pending. - Trạng thái tài khoản được đọc lại từ cơ sở dữ liệu ở mọi yêu cầu đã xác thực, nên phiên không bao giờ tồn tại lâu hơn trạng thái
activecủa tài khoản.
Quản trị viên sẽ thấy:
- Quản lý người dùng hiển thị thẻ Phê duyệt đang chờ liệt kê các tài khoản chờ, mỗi tài khoản có hành động Kích hoạt tài khoản và hành động từ chối. Từ chối nghĩa là xóa; không có trạng thái tạm ngưng riêng.
- Quản trị viên nhận thông báo trong ứng dụng khi đã đăng nhập: huy hiệu tại mục Người dùng và thông báo nổi khi có đăng ký mới. Bản tóm tắt phê duyệt đang chờ được thăm dò khoảng mỗi phút một lần (
GET /api/users/pending-approvals, chỉ quản trị viên). - Phê duyệt (
PATCH /api/users/:id/approve, chỉ quản trị viên) ghi lại quản trị viên nào đã duyệt và thời điểm. Việc này không đổi vai trò: tài khoản được duyệt giữ vai tròuserđến khi quản trị viên nâng cấp. Phê duyệt có hiệu lực ở lần đăng nhập tiếp theo; không cần tạo lại gì.
Tài khoản hiện có không bị ảnh hưởng khi nâng cấp: chỉ tài khoản được tạo qua đăng ký công khai sau khi tính năng phát hành mới bắt đầu ở trạng thái chờ. Tài khoản do quản trị viên tạo từ Quản lý người dùng hoạt động ngay.
Chủ động bật đăng ký công khai
Đăng ký mặc định bị tắt. Chỉ đặt biến môi trường backend sau trong khoảng thời gian cần chấp nhận tài khoản cục bộ hoặc OAuth mới:
ENABLE_SIGNUP=true
Đưa về false sau khoảng đăng ký đã lên kế hoạch. Người dùng cục bộ và OAuth hiện có vẫn đăng nhập được, còn quản trị viên vẫn có thể tạo tài khoản từ Quản lý người dùng khi đăng ký công khai bị đóng.
Cơ sở dữ liệu trống luôn cho phép một quản trị viên cục bộ ngay cả khi ENABLE_SIGNUP=false; OAuth không thể chiếm vị trí ban đầu đó. Với bản triển khai từ xa riêng tư, hãy đặt tên máy chủ sau danh sách cho phép danh tính như Cloudflare Access trước khi khởi động ứng dụng, rồi tạo quản trị viên đầu tiên qua tuyến được bảo vệ.
Vai trò
| Vai trò | Mục đích |
|---|---|
admin | Quản trị phiên bản, quản lý người dùng, cài đặt hệ thống và vận hành runtime Work đáng tin cậy |
user | Các quy trình trò chuyện, mô hình, persona, tài liệu và cài đặt thông thường |
Cài đặt, xóa, sao chép, đẩy và dỡ mô hình chỉ dành cho quản trị viên vì các thao tác này thay đổi tài nguyên máy chủ.
Quyền truy cập Work
Work mặc định chỉ dành cho quản trị viên vì cho phép mô hình đã chọn thực thi lệnh tùy ý trong container được quản lý. Quản trị viên có thể mở Work cho mọi người dùng đang hoạt động từ tab Quản lý người dùng trong Cài đặt; cài đặt tồn tại qua khởi động lại và có hiệu lực ngay, kể cả với phiên terminal đang mở. Không gian làm việc thư mục máy chủ luôn chỉ dành cho quản trị viên vì bind-mount đường dẫn máy chủ. Hãy xem mọi người được cấp Work là nhà vận hành runtime đáng tin cậy, không chỉ là người dùng WebUI.
Quyền quản trị được kiểm tra theo vai trò hiện tại trong cơ sở dữ liệu thay vì chỉ vai trò lưu trong JWT hiện có. Vì vậy, hạ quyền quản trị viên sẽ thu hồi Work ngay. Backend sau đó cố hủy các lượt chạy đang hoạt động và dừng container cùng bản xem trước Work của người dùng, đồng thời giữ bản ghi tác vụ và volume có tên. Nếu dọn dẹp Docker thất bại, quyền vẫn bị thu hồi, thay đổi vai trò báo lỗi dọn dẹp và nhà vận hành phải khôi phục quyền Docker rồi thử lại.
Xóa người dùng sẽ phá hủy dữ liệu Work của họ. Libre WebUI trước tiên dừng container được quản lý và xóa volume Work, sau đó xóa tài khoản cùng bản ghi cơ sở dữ liệu. Nếu Docker không thể chứng minh dọn dẹp thành công, thao tác xóa tài khoản thất bại để quản trị viên sửa sự cố runtime rồi thử lại.
Nhóm và cấp quyền tài nguyên
Quản trị viên có thể tạo nhóm và quản lý thành viên từ tab Quản lý người dùng trong Cài đặt. Nhóm là chủ thể được cấp tài nguyên: chủ sở hữu cuộc trò chuyện, ghi chú, tài liệu, bộ sưu tập kiến thức, thư mục, persona, prompt, kỹ năng hoặc lịch có thể cấp quyền read, write hoặc admin cho người dùng hay nhóm qua API truy cập—mọi bề mặt chia sẻ đều dùng cùng hộp thoại (xem Chia sẻ)—và quản trị viên có thể giới hạn máy chủ công cụ đã đăng ký cho người dùng hoặc nhóm tương tự. Tài nguyên mặc định vẫn riêng tư—vai trò admin toàn cục không cấp quyền vào nội dung người dùng khác. Tư cách thành viên được đánh giá lúc yêu cầu, nên xóa thành viên sẽ thu hồi ngay quyền từ nhóm. Chế độ xem "quyền hiệu lực" trong tab Quản lý người dùng ở Cài đặt trả lời "vì sao người dùng này truy cập được?" bằng cách liệt kê vai trò, nhóm, quyền tính năng và mọi quyền cấp đến họ.
Nhật ký kiểm toán bảo mật
Các hành động nhạy cảm về bảo mật—đăng nhập và thất bại, đăng xuất, thu hồi phiên và token, thay đổi người dùng, nhóm, quyền cấp và token—được ghi trong nhật ký kiểm toán chỉ thêm, tách biệt với phân tích mức sử dụng. Chi tiết được biên tập trước khi lưu: khóa giống bí mật bị bỏ và kích thước payload bị giới hạn, nên mật khẩu, token và nội dung prompt không bao giờ vào nhật ký. Thay đổi nhóm và quyền cấp ghi sự kiện kiểm toán trong cùng giao dịch cơ sở dữ liệu, nên không thể có thay đổi mà không có dấu vết. Quản trị viên có thể truy vấn nhật ký từ tab Quản lý người dùng trong Cài đặt; thời gian giữ mặc định là 180 ngày (AUDIT_RETENTION_DAYS).
Phiên
Backend ký JWT bằng JWT_SECRET. Hãy đặt bí mật ổn định trong production:
JWT_SECRET=replace-with-a-long-random-secret
Đổi JWT_SECRET làm mất hiệu lực các phiên hiện có. Token đăng nhập cục bộ và OAuth dùng JWT_EXPIRES_IN, mặc định 7d; đổi giá trị này ảnh hưởng các phiên mới. Kết nối WebSocket đổi token bền vững lấy vé dùng một lần, tồn tại ngắn và đóng khi phiên nền hết hạn.
Mỗi lần đăng nhập cũng tạo bản ghi phiên phía máy chủ gắn vào JWT. Cài đặt → Phiên liệt kê từng thiết bị cùng phương thức đăng nhập, hoạt động đầu/cuối và thời điểm hết hạn. Thu hồi phiên tại đó (hoặc "Đăng xuất các phiên khác") lập tức vô hiệu token trên mọi replica và đóng kết nối WebSocket đang hoạt động; đăng xuất thu hồi phiên hiện tại tương tự. Token phát hành trước tính năng này không có ID phiên và vẫn hợp lệ đến khi hết hạn, ngoại trừ "đăng xuất các phiên khác" từ lần đăng nhập mới cũng đặt mốc cắt theo tài khoản để từ chối chúng.
Xác thực hai yếu tố và passkey
Cài đặt → Phiên quản lý cả yếu tố thứ hai và đăng nhập không mật khẩu:
- Ứng dụng xác thực (TOTP). Đăng ký hiển thị bí mật base32 và liên kết
otpauth://cho mọi ứng dụng xác thực; xác nhận mã 6 chữ số đầu tiên sẽ kích hoạt và hiển thị mười mã khôi phục dùng một lần. Sau đó, đăng nhập bằng mật khẩu trả về thử thách tồn tại ngắn thay vì phiên, vàPOST /api/auth/mfa/verifyhoàn tất đăng nhập bằng mã TOTP hoặc mã khôi phục. Bước thời gian của mỗi mã được chấp nhận được ghi lại để mã bị chặn không thể phát lại; mã khôi phục chỉ được lưu dưới dạng token tra cứu một chiều có khóa và mỗi mã dùng đúng một lần. Tắt hoặc tạo lại mã khôi phục yêu cầu chứng minh lại yếu tố. - Passkey (WebAuthn). "Đăng nhập bằng passkey" thực hiện đăng nhập không mật khẩu với thông tin xác thực có thể khám phá; xác minh người dùng (khóa màn hình, sinh trắc học hoặc PIN) bắt buộc khi đăng ký và đăng nhập. Chứng thực được nhận là
none, hỗ trợ thông tin ES256 và EdDSA, còn vật liệu xác thực được mã hóa khi lưu với ID giữ dưới dạng token tra cứu có khóa. Thử thách dùng một lần và hết hạn sau năm phút; bộ đếm chữ ký khác không mà không tăng bị từ chối như dấu hiệu nhân bản. Passkey cần origin an toàn (HTTPS), hoặclocalhosttrong phát triển; đặtWEBAUTHN_RP_IDkhi phiên bản được truy cập qua nhiều tên máy chủ.
Token thử thách MFA phát hành sau mật khẩu đúng được ký bằng bí mật dẫn xuất từ (nhưng khác với) JWT_SECRET: nó không bao giờ có thể xác thực yêu cầu API, gắn với một tài khoản và một mục đích, rồi bị tiêu thụ khi thành công.
Quản trị viên có thể yêu cầu yếu tố thứ hai cho mọi tài khoản (Người dùng → thẻ chính sách hai yếu tố, hoặc ghim bằng MFA_REQUIRED_MODE=required). Người dùng chưa có sẽ được hướng dẫn đăng ký ở lần đăng nhập tiếp theo trước khi cấp phiên. Quản trị viên cũng có thể đặt lại đăng ký TOTP từ danh sách người dùng để khôi phục tài khoản; passkey được giữ vì người dùng tự quản lý trong cài đặt. Đăng ký, kích hoạt, lỗi xác minh, tắt, đổi chính sách, thêm/xóa passkey và đặt lại bởi quản trị viên đều được ghi trong nhật ký kiểm toán bảo mật.
MFA áp dụng cho đăng nhập bằng mật khẩu. Đăng nhập OAuth và OIDC dựa vào yếu tố thứ hai của nhà cung cấp danh tính và không bị thử thách lại. Token API không bị ảnh hưởng vì không dùng xác thực phiên.
Token API
Cài đặt → Khóa API tạo token truy cập cá nhân (tiền tố lwk_) để sử dụng bằng chương trình. Bí mật chỉ hiển thị một lần và chỉ lưu dưới dạng hash. Mỗi token mang danh sách phạm vi rõ ràng (chat, models, documents, notes, personas, media, work, admin); backend ánh xạ từng họ tuyến với phạm vi bắt buộc, nên token chỉ dành cho ghi chú không thể truy cập trò chuyện hay quản trị, và quản lý phiên không bao giờ dùng được bằng token. Token hỗ trợ thời hạn tùy chọn, theo dõi lần dùng cuối, có thể thu hồi bất cứ lúc nào và bị giới hạn tốc độ theo token trên mọi replica. Token phạm vi admin chỉ do quản trị viên tạo và vẫn yêu cầu tài khoản giữ vai trò admin khi sử dụng. Token phạm vi chat cũng là khóa cho API /v1 công khai tương thích OpenAI.
Cloudflare Turnstile
Turnstile bảo vệ đăng nhập và đăng ký bằng mật khẩu khi cả hai khóa được cấu hình:
TURNSTILE_SITE_KEY=...
TURNSTILE_SECRET_KEY=...
TURNSTILE_EXPECTED_HOSTNAME=chat.example.com
Frontend gán hai hành động login và signup riêng. Backend xác minh token với Cloudflare và từ chối phản hồi có tên máy chủ hoặc hành động không khớp yêu cầu. BASE_URL cung cấp tên máy chủ mong đợi khi TURNSTILE_EXPECTED_HOSTNAME không được đặt rõ.
Nếu thiếu một trong hai khóa, Turnstile bị tắt.
GitHub OAuth
Cấu hình:
GITHUB_CLIENT_ID=...
GITHUB_CLIENT_SECRET=...
GITHUB_CALLBACK_URL=https://your-domain.example/api/auth/oauth/github/callback
Luồng GitHub OAuth tạo người dùng cục bộ có tên tiền tố gh_ và mặc định gán vai trò user.
Hugging Face OAuth
Cấu hình:
HUGGINGFACE_CLIENT_ID=...
HUGGINGFACE_CLIENT_SECRET=...
HUGGINGFACE_CALLBACK_URL=https://your-domain.example/api/auth/oauth/huggingface/callback
Luồng Hugging Face OAuth tạo người dùng cục bộ có tên tiền tố hf_ và mặc định gán vai trò user.
Cả hai nhà cung cấp OAuth dùng giá trị state ngẫu nhiên mật mã, gắn với cookie HttpOnly, SameSite tồn tại ngắn. Callback từ chối state bị thiếu hoặc không khớp. Sau callback thành công, JWT quay lại frontend trong cookie HttpOnly 60 giây, được trao đổi và xóa ngay; token bearer không bao giờ xuất hiện trong URL callback, lịch sử trình duyệt hoặc header referrer.
Chuyển hướng và CORS
Đặt BASE_URL cho giá trị callback mặc định và CORS_ORIGIN cho quyền truy cập trình duyệt:
BASE_URL=https://your-domain.example
CORS_ORIGIN=https://your-domain.example
Với phát triển cục bộ, hãy thêm origin phát triển Vite:
CORS_ORIGIN=http://localhost:5173,http://127.0.0.1:5173
Chế độ demo
Chế độ demo là chế độ xem trước frontend. Nó điền sẵn thông tin demo bị vô hiệu hóa và dùng phản hồi API giả lập. Đây không phải chế độ xác thực production.
Danh sách kiểm tra bảo mật
- Đặt
JWT_SECRETmạnh. - Giữ
DATA_DIRtrên bộ nhớ bền vững có kiểm soát truy cập. - Sao lưu
ENCRYPTION_KEYcùng cơ sở dữ liệu. - Cấu hình Turnstile cho đăng ký công khai.
- Dùng HTTPS cho bản triển khai công khai.
- Giới hạn khóa API nhà cung cấp ở phạm vi tối thiểu cần thiết.
- Giữ URL callback OAuth chính xác.
- Chỉ cấp Work (tài khoản quản trị viên hoặc chế độ mở cho mọi người dùng) cho người đáng tin cậy để vận hành runtime container của backend.