Apache Derby Bài 37: Xác thực người dùng (Authentication) và Phân quyền truy cập (Authorization)
1. Bức tường an ninh 2 lớp (AuthN & AuthZ)
Từ đầu series đến giờ, chúng ta đã thao tác với cơ sở dữ liệu mà không hề cần đến tài khoản hay mật khẩu (hoặc gõ bất kỳ user/pass nào cũng được chấp nhận). Trong môi trường phát triển (Dev) hoặc chế độ Embedded cho cá nhân, sự dễ dãi này mang lại sự tiện lợi. Nhưng khi đẩy lên môi trường Production (Network Server), việc mở toang cửa CSDL là một thảm họa.
Để bảo mật hệ thống, Apache Derby cung cấp bức tường an ninh 2 lớp:
-
Xác thực danh tính - Authentication (Ai đang kết nối?): Yêu cầu người dùng phải cung cấp đúng Tên đăng nhập (Username) và Mật khẩu (Password) thì mới được phép thiết lập kết nối (Connection) tới hệ thống.
-
Phân quyền truy cập - Authorization (Người đó được làm gì?): Sau khi đã vào được hệ thống, hệ thống sẽ kiểm tra xem người này có quyền xem (
SELECT), thêm (INSERT), sửa (UPDATE) hay xóa (DELETE) trên một bảng cụ thể hay không.
2. Lớp 1: Bật tính năng Xác thực tích hợp (BUILTIN Authentication)
Derby hỗ trợ xác thực qua các hệ thống tập trung của doanh nghiệp như LDAP (Lightweight Directory Access Protocol) hoặc viết các lớp Java tự định nghĩa. Tuy nhiên, cách đơn giản và phổ biến nhất cho các ứng dụng nhỏ là sử dụng chế độ BUILTIN (Danh sách tài khoản lưu trực tiếp trong Derby).
Mở tệp derby.properties (đã tạo ở Bài 23) và thêm các cấu hình sau:
Properties
# 1. Bắt buộc mọi kết nối phải có tài khoản/mật khẩu
derby.connection.requireAuthentication=true
# 2. Sử dụng cơ chế kiểm tra tài khoản tích hợp sẵn của Derby
derby.authentication.provider=BUILTIN
# 3. Khai báo danh sách người dùng theo cú pháp: derby.user.<TÊN_USER>=<MẬT_KHAU>
derby.user.admin=MatKhauSieuKho123
derby.user.nhan_vien_1=NhanVien2026
derby.user.khach_hang=Khach123
(Lưu ý: Bạn phải khởi động lại Derby Network Server để các cấu hình này có hiệu lực).
Thay đổi chuỗi kết nối JDBC
Lúc này, nếu ứng dụng Java của bạn cố gắng kết nối bằng chuỗi URL cũ, Derby sẽ ném ra lỗi từ chối truy cập. Bạn bắt buộc phải truyền user và password vào URL (hoặc qua đối tượng Properties trong JDBC):
Java
// Cách 1: Gắn trực tiếp vào URL
String url = "jdbc:derby://localhost:1527/my_company_db;user=nhan_vien_1;password=NhanVien2026";
Connection conn = DriverManager.getConnection(url);
// Cách 2: Chuyên nghiệp hơn, truyền qua tham số
Connection conn2 = DriverManager.getConnection("jdbc:derby://localhost:1527/my_company_db", "admin", "MatKhauSieuKho123");
3. Lớp 2: Kích hoạt Phân quyền (SQL Authorization)
Đây là một "cạm bẫy" bảo mật cực kỳ nguy hiểm trong Derby: Dù bạn đã bật Xác thực (Authentication), thì theo mặc định, BẤT KỲ AI đăng nhập thành công cũng đều có toàn quyền (Full Access) trên toàn bộ cơ sở dữ liệu. Anh khach_hang hoàn toàn có thể chạy lệnh DROP TABLE san_pham của anh admin.
Để ngăn chặn, bạn BẮT BUỘC phải bật tính năng Phân quyền SQL bằng cách thêm dòng sau vào derby.properties:
Properties
# Bật tính năng kiểm tra quyền hạn (GRANT/REVOKE)
derby.database.sqlAuthorization=true
# Tùy chọn: Chỉ định ai là Chủ sở hữu tối cao (Database Owner - DBO)
derby.database.defaultConnectionMode=noAccess
derby.database.fullAccessUsers=admin
Khi tính năng này được bật, nguyên tắc phân quyền của Derby hoạt động như sau:
-
Database Owner (Chủ sở hữu CSDL): Người đầu tiên tạo ra cơ sở dữ liệu (tạo với
create=true) sẽ là chủ sở hữu. Người này có toàn quyền tối cao, không ai chặn được. -
Schema/Table Owner (Chủ sở hữu bảng): Nếu anh
nhan_vien_1tạo ra bảngbao_cao, anh ta là chủ bảng. Mặc định, CHỈ CÓ anh ta và Database Owner mới được phép thao tác trên bảng đó. Những người khác sẽ bị từ chối truy cập trừ khi được cấp quyền (Cấm mặc định - Default Deny).
4. Quản trị quyền hạn với lệnh GRANT và REVOKE
Để chia sẻ quyền truy cập bảng cho người khác, Chủ sở hữu (Owner) sử dụng câu lệnh SQL chuẩn ANSI: GRANT (Cấp quyền) và REVOKE (Thu hồi quyền).
4.1. Lệnh GRANT (Cấp quyền)
Chỉ định những thao tác cụ thể mà một User được phép làm.
SQL
-- Đăng nhập bằng tài khoản 'admin' và cấp quyền cho 'nhan_vien_1'
-- 1. Cấp quyền ĐỌC (SELECT) trên bảng 'san_pham'
GRANT SELECT ON san_pham TO nhan_vien_1;
-- 2. Cấp quyền THÊM và SỬA (Không cho xóa) trên bảng 'don_hang'
GRANT INSERT, UPDATE ON don_hang TO nhan_vien_1;
-- 3. Cấp quyền thực thi một UDF / Procedure
GRANT EXECUTE ON PROCEDURE TANG_DIEM_KHACH_HANG TO nhan_vien_1;
4.2. Lệnh REVOKE (Thu hồi quyền)
Rút lại các quyền đã cấp trước đó.
SQL
-- Rút quyền UPDATE của 'nhan_vien_1' trên bảng 'don_hang'
REVOKE UPDATE ON don_hang FROM nhan_vien_1;
-- Rút TẤT CẢ các quyền trên bảng 'san_pham'
REVOKE ALL PRIVILEGES ON san_pham FROM nhan_vien_1;
5. Thực hành: Kiểm thử bức tường an ninh
Giả sử bạn dùng DBeaver hoặc mã Java để đăng nhập bằng tài khoản khach_hang (tài khoản này mới được tạo trong derby.properties nhưng chưa được cấp bất kỳ quyền gì).
Bạn thử chạy câu lệnh:
SQL
SELECT * FROM admin.san_pham;
Derby Engine sẽ lập tức chặn lại và ném ra ngoại lệ SQLException:
-
SQLState:
28502 -
Message:
User 'KHACH_HANG' does not have SELECT permission on column 'ID' of table 'ADMIN'.'SAN_PHAM'.
Ứng dụng của bạn đã được bảo vệ hoàn toàn ở cấp độ cơ sở dữ liệu. Dù tin tặc có dịch ngược được mã nguồn Java, chúng cũng không thể khai thác lỗ hổng nếu không có tài khoản được cấp quyền tương ứng.
6. Tổng kết
-
Authentication (Ai?): Cấu hình qua
derby.properties(bậtrequireAuthenticationvàprovider=BUILTIN) để buộc người dùng nhập Tên/Mật khẩu. -
Authorization (Được làm gì?): Cấu hình
sqlAuthorization=trueđể kích hoạt cơ chế bảo vệ bảng. -
Quy tắc sở hữu: Ai tạo bảng, người đó là chủ. Chủ bảng phải dùng lệnh
GRANTđể mở quyền cho người khác, và dùngREVOKEđể thu hồi. -
Kết hợp mã hóa đĩa (Bài 36) và bảo mật người dùng (Bài 37), Apache Derby trở thành một pháo đài dữ liệu cực kỳ kiên cố cho các ứng dụng doanh nghiệp.
Chúng ta đã xử lý xong các thao tác nghiệp vụ, tối ưu và bảo mật. Bài tiếp theo sẽ đề cập đến cách lưu trữ các loại dữ liệu đặc thù, rất phổ biến nhưng không thể lưu bằng các kiểu INT hay VARCHAR thông thường: Apache Derby Bài 38: Xử lý dữ liệu lớn (Lưu trữ Hình ảnh và Văn bản siêu dài với BLOB/CLOB).
All rights reserved