Queryable Encryption
Queryable Encryption cho phép ứng dụng của bạn truy vấn dữ liệu đã mã hóa mà không để lộ giá trị gốc cho database. Các field vẫn ở dạng mã hóa trên mọi chặng bên ngoài ứng dụng, kể cả khi được lưu và truy vấn trên cluster. Ứng dụng của bạn mã hóa giá trị trước khi gửi tới MongoDB, và giải mã khi giá trị trả về. Nhờ vậy bạn tìm kiếm được trên field đã mã hóa mà dữ liệu nhạy cảm vẫn được bảo vệ.
So với các cơ chế mã hóa khác
Mỗi cơ chế bảo vệ một giai đoạn khác nhau trong vòng đời dữ liệu.
| Cơ chế | Bảo vệ dữ liệu | Server thấy plaintext |
|---|---|---|
| SSL/TLS | Khi truyền trên mạng | Có |
| Mã hóa ổ đĩa (TDE) | Khi lưu trên đĩa | Có, server tự giải mã để xử lý |
| Queryable Encryption | Khi truyền, khi lưu và khi đang xử lý | Không |
Ba cơ chế bổ sung cho nhau chứ không thay thế nhau. Chỉ cột cuối mới thay đổi được những gì một người có quyền đọc database nhìn thấy.
Cơ chế hoạt động
Code ứng dụng không phải đổi hình dạng. Bạn ghi {ssn: "123-45-6789"} và đọc ra đúng như vậy, còn driver cùng thư viện crypt_shared lo mã hóa lúc gửi đi và giải mã lúc nhận về.

Hàng giữa mới là thứ khiến cơ chế này vượt xa mã hóa phía client thông thường. Driver mã hóa cả filter tìm kiếm, nhờ vậy server so khớp ciphertext với ciphertext và trả về đúng bản ghi mà không biết bạn đã tìm gì.
Những truy vấn nào vẫn chạy được
Việc so khớp chỉ hoạt động với query type bạn khai báo lúc tạo collection, và lựa chọn này là vĩnh viễn suốt vòng đời collection.
| Query type | Dùng cho | Trạng thái |
|---|---|---|
equality | $eq, $in, $ne | Dùng được trong production từ MongoDB 7.0 |
range | $lt, $lte, $gt, $gte | Dùng được trong production từ MongoDB 8.0 |
prefix, suffix, substring | Tìm theo tiền tố, hậu tố, chuỗi con | Dùng được trong production từ MongoDB 9.0 |
none | Chỉ mã hóa, không truy vấn | Luôn có |
Phiên bản 8.0.20 cho bạn equality và range, còn 7.0.30 chỉ cho equality. Phiên bản 6.0.27 không dùng được, vì MongoDB 6.0 chỉ phát hành Queryable Encryption dưới dạng public preview và bản preview đó nay đã ngừng hỗ trợ.
Những giới hạn cần tính trước
Mã hóa một field đồng nghĩa với thu hẹp những gì bạn làm được với nó. Hãy đối chiếu danh sách này với truy vấn thật của ứng dụng trước khi chốt schema.
Giới hạn đầu tiên chi phối mọi thứ còn lại. Bạn chỉ bật được Queryable Encryption trên collection mới và rỗng, và sau đó không đổi được danh sách field mã hóa. Chọn sai nghĩa là phải tạo collection mới rồi migrate dữ liệu.
Các giới hạn còn lại áp dụng cho chính những field đã mã hóa.
- Một collection không dùng đồng thời Queryable Encryption và CSFLE.
- Không hỗ trợ
collation. - Không hỗ trợ
updateManyvàdeleteMany, cònbulkWritechỉ được một namespace. - Update trên field mã hóa chỉ nhận
$setvà$unset, không nhận$inchay$push. findOneAndUpdatevàfindOneAndReplacephải trả về bản ghi trước khi sửa (returnDocument: before) và không dùng được projection.- Truy vấn field mã hóa với
null, với regex, hoặc so sánh với field mã hóa khác đều lỗi. - Trong aggregation, không dùng được
$outvà$merge, còn$groupchỉ chạy trên field không mã hóa. - Không dùng được
distinct. - Phải xóa collection bằng client đã bật Queryable Encryption, nếu không các collection metadata sẽ còn sót lại.
Danh sách đầy đủ có trong tài liệu Supported Operations for Queryable Encryption của MongoDB.
Các bước thiết lập
Trình tự giống nhau ở mọi ngôn ngữ, và hai trang tiếp theo sẽ đi qua từng dòng code.

Tạo master key
Khi dùng thử, đây là file local chứa 96 byte ngẫu nhiên, đọc một lần lúc ứng dụng khởi động. Lên production thì thay bằng KMS (AWS, Azure, GCP hoặc KMIP).
Khai báo các field
Mỗi field mã hóa cần path, bsonType và queryType. Chính queryType quyết định toán tử nào còn chạy được trên field đó, và không đổi được sau khi collection đã tạo.
Tạo collection
Một lệnh làm ba việc. Driver sinh một Data Encryption Key cho từng field, server tạo collection, và server tạo thêm các collection metadata enxcol_.<COLLECTION>.esc và enxcol_.<COLLECTION>.ecoc bên cạnh. Collection phải chưa tồn tại.
Tạo client có mã hóa
Đây là client thứ hai, tách khỏi client thường đã tạo collection. Nó nhận field map mà bước 3 trả về, lúc này đã có keyId do driver sinh ra. Bước 3 và 4 bắt buộc theo đúng thứ tự đó, vì field map chỉ có keyId sau khi collection đã được tạo.
Đọc và ghi
Từ đây collection hoạt động như mọi collection khác. Driver mã hóa các field đã khai báo trước khi chúng rời tiến trình, và giải mã khi bản ghi trả về.
Dữ liệu đã mã hóa bằng master key bị mất là không thể khôi phục. Hãy backup file khóa ở nơi tách biệt với database, và chuyển sang KMS trước khi đưa dữ liệu thật vào.
Kiểm tra xem đã chạy đúng chưa
Sau khi script chạy xong, cùng một bản ghi sẽ hiện ra hoàn toàn khác nhau tùy client nào đọc nó.
- Qua client đã bật mã hóa,
ssnđọc ra là plaintext. - Qua client thường, hoặc
mongoshkhông có khóa,ssnlàBinDatasubtype 6 và bản ghi có thêm field__safeContent__. - Tìm theo giá trị plaintext qua client thường thì không trả về gì cả.
Lỗi thường gặp
Bảng dưới ánh xạ từng thông báo lỗi sang nguyên nhân của nó.
| Lỗi | Nguyên nhân và cách xử lý |
|---|---|
Không tìm thấy mongo_crypt_v1.so | Sai đường dẫn, hoặc chưa cài crypt_shared trên máy chạy ứng dụng |
Lỗi phiên bản crypt_shared | crypt_shared phải bằng hoặc mới hơn phiên bản server |
Multi-document updates are not allowed with Queryable Encryption | Code đang gọi updateMany. Chuyển sang updateOne |
Invalid match expression operator on encrypted field | Toán tử không được hỗ trợ cho query type của field đó, ví dụ regex hoặc $gt trên field equality |
findAndModify with encryption only supports new: false | Lệnh đang dùng returnDocument: after. Đổi sang before |
| Collection đã tồn tại | Queryable Encryption cần collection mới và rỗng. Hãy xóa nó bằng client đã bật mã hóa trước |
| Lỗi xác thực khi kết nối | Password có ký tự đặc biệt chưa được URL-encode |
Khuyến nghị cho production
Các ví dụ dùng file khóa local cho đơn giản ở lần chạy đầu. Hãy đổi những điểm sau trước khi đưa dữ liệu thật vào.
- Dùng KMS (AWS, Azure, GCP hoặc KMIP) thay cho khóa local. Khóa local nằm trong file, nên ai lấy được file đó là giải mã được toàn bộ dữ liệu mà nó bảo vệ.
- Không ghi password vào source code. Hãy đọc từ biến môi trường hoặc secret manager.
- Chỉ mã hóa những field thật sự cần. Mỗi field mã hóa phải trả giá bằng sự linh hoạt khi truy vấn và bằng dung lượng, qua các collection metadata
enxcol_.*và field__safeContent__. - Quyết định field nào cần truy vấn trước khi tạo collection, vì lựa chọn đó về sau không sửa được.
- Kiểm thử truy vấn thật của ứng dụng với danh sách toán tử được hỗ trợ trước khi triển khai, đừng để sau mới thử.
Tài liệu tham khảo
Các trang dưới đây là tài liệu chính thức của MongoDB, đi sâu hơn những gì hướng dẫn này nói.
- Queryable Encryption là trang gốc của tính năng trong tài liệu MongoDB.
- Compatibility liệt kê phiên bản server, driver, bản phát hành và kiểu cluster nào hỗ trợ tính năng này.
- Limitations có danh sách giới hạn đầy đủ, gồm cả những điều trang này không nhắc lại.
- Supported operations bao quát mọi lệnh và toán tử chạy được trên field đã mã hóa.
- Quick start là hướng dẫn thực hành của chính MongoDB, có cho nhiều ngôn ngữ.
- Automatic Encryption Shared Library hướng dẫn cách tải và cấu hình
crypt_shared.