- Từ phiên bản DuckDB 1.4, tính năng mã hóa dữ liệu lưu trữ (Data-at-Rest Encryption) đã được bổ sung, cho phép bảo vệ toàn bộ tệp cơ sở dữ liệu bằng mã hóa chuẩn dựa trên AES
- Các thuật toán được hỗ trợ là AES-GCM-256 và AES-CTR-256; trong đó GCM bao gồm thẻ xác thực (tag) để kiểm tra tính toàn vẹn dữ liệu
- Mã hóa được áp dụng cho tệp cơ sở dữ liệu, WAL (Write-Ahead Log) và tệp tạm, đồng thời bao gồm cấu trúc bộ nhớ đệm an toàn để quản lý khóa và bảo vệ bộ nhớ
- Có hai triển khai là OpenSSL và Mbed TLS; khi dùng OpenSSL, nhờ tăng tốc phần cứng nên gần như không có suy giảm hiệu năng
- Tệp DuckDB được mã hóa có thể đảm bảo đồng thời tính bảo mật và tính di động, cho phép phân phối dữ liệu an toàn ngay cả trong môi trường đám mây hoặc CDN
Tổng quan về mã hóa
- Từ DuckDB 1.4, có thể mã hóa minh bạch (Transparent Encryption) toàn bộ tệp cơ sở dữ liệu
- Khi lưu, sử dụng mã hóa AES-GCM-256 hoặc AES-CTR-256
- AES-GCM tính thẻ để kiểm tra tính toàn vẹn, còn AES-CTR nhanh hơn nhưng không có chức năng xác thực
- AES là thuật toán mã hóa khóa đối xứng, dùng cùng một khóa cho cả mã hóa và giải mã
- Sử dụng IV (Initialization Vector) và nonce để đảm bảo cùng một bản rõ sẽ được biến đổi thành các bản mã khác nhau
- Hiện vẫn chưa hoàn toàn đáp ứng các yêu cầu tiêu chuẩn của NIST
Cấu trúc triển khai bên trong DuckDB
- Header chính của tệp cơ sở dữ liệu được giữ ở dạng văn bản thuần, lưu cờ cho biết có mã hóa hay không cùng siêu dữ liệu mã hóa
- Siêu dữ liệu bao gồm định danh cơ sở dữ liệu (salt), thông tin thuật toán mã hóa và canary đã được mã hóa
- Thông qua hàm dẫn xuất khóa (KDF), khóa do người dùng nhập được chuyển thành khóa bảo mật 32 byte
- Khóa đã dẫn xuất được lưu trong bộ nhớ đệm an toàn để không bị hoán đổi ra đĩa
- Khóa gốc bị xóa ngay khỏi bộ nhớ
- Các khối dữ liệu được lưu theo đơn vị mặc định 256KB; khi mã hóa, nonce/IV và tag được thêm vào header của khối, khiến kích thước tăng thêm 40 byte
- Checksum được lưu ở dạng đã mã hóa
Mã hóa WAL (Write-Ahead Log)
- WAL là tệp log dùng để khôi phục giao dịch, và trong DuckDB nó được mã hóa theo từng mục
- Mỗi mục được thêm nonce và tag để được bảo vệ theo cơ chế AES-GCM
- Một mục WAL đã mã hóa có cấu trúc theo thứ tự: độ dài (bản rõ) → nonce → checksum và dữ liệu đã mã hóa → tag
- Với cơ sở dữ liệu có chỉ định khóa mã hóa, mã hóa WAL sẽ được tự động kích hoạt
Mã hóa tệp tạm
- Tệp tạm được tạo ra trong các phép toán lớn như sắp xếp, join, hàm cửa sổ cũng sẽ được mã hóa tự động
- Được kích hoạt khi kết nối tới cơ sở dữ liệu đã mã hóa hoặc đặt
SET temp_file_encryption = true
- DuckDB tự tạo khóa tạm thời nội bộ; nếu xảy ra xung đột thì sẽ không thể giải mã
- Tệp tạm có phần mở rộng
.tmp hoặc .block, và thông tin kích thước được chứa trong header
- Checksum được lược bỏ để giảm chi phí tính toán
Cách sử dụng mã hóa
Triển khai và hiệu năng
- DuckDB bao gồm hai triển khai mã hóa là Mbed TLS và OpenSSL để giảm thiểu phụ thuộc bên ngoài
- Mbed TLS có hiệu năng thấp do không bật tăng tốc phần cứng, và sau khi phát hiện lỗ hổng trong bộ sinh số ngẫu nhiên, chức năng ghi đã bị vô hiệu hóa (từ 1.4.1 trở đi)
- OpenSSL sử dụng tăng tốc phần cứng và bộ sinh số ngẫu nhiên an toàn, đồng thời tự động chuyển sang dùng khi nạp extension
httpfs
- Kết quả kiểm tra hiệu năng:
- Truy vấn SUMMARIZE không mã hóa: 5.4 giây
- Mã hóa bằng Mbed TLS: 6.2 giây
- Mã hóa bằng OpenSSL: 5.4 giây (không suy giảm hiệu năng)
- Trong các bài kiểm tra TPC-H Power/Throughput, khi dùng mã hóa thì chênh lệch hiệu năng là rất nhỏ
- Power@Size: 624,296 → 571,985
- Throughput@Size: 450,409 → 145,353 (giảm nhẹ khi I/O đĩa tăng)
Kết luận
- Với tính năng mã hóa dữ liệu lưu trữ của DuckDB, có thể bảo vệ an toàn toàn bộ tệp cơ sở dữ liệu
- Ngay cả WAL và tệp tạm cũng được mã hóa, giúp giảm rủi ro rò rỉ dữ liệu trong môi trường đám mây
- Triển khai dựa trên OpenSSL gần như không gây tổn thất hiệu năng, nên có thể sử dụng hiệu quả trong môi trường thực tế
- Tệp DuckDB được mã hóa cũng phù hợp để phân phối ra bên ngoài như qua CDN, đồng thời vẫn giữ nguyên các tính năng hiện có như lưu trữ nhiều bảng
- Nhóm DuckDB dự định sẽ tiếp tục cải thiện tính năng này dựa trên phản hồi của người dùng
1 bình luận
Ý kiến trên Hacker News
Độ nhạy với việc tái sử dụng nonce của AES-GCM là phần khó khi triển khai
Tài liệu có nhắc đến điều này nhưng không chia sẻ cách giải quyết
Header lại chứa nonce 16 byte thay vì 12 byte, và cũng không nói rõ byte nào là ngẫu nhiên nên khá khó hiểu. Không biết có phải tôi đã bỏ sót điều gì không
Tôi vẫn tiếp tục ngạc nhiên trước những gì đội DuckDB làm được
Trước đây tôi từng làm một giải pháp đơn giản để mã hóa tệp DuckDB bằng OpenSSL, nhưng lúc chạy truy vấn đầu tiên thì thời gian thực thi tăng gấp đôi và còn tốn nhiều bộ nhớ
Trong khi đó DuckDB dùng mã hóa theo từng trang và tận dụng tăng tốc AES của CPU nên chi phí đọc/ghi gần như không đáng kể
Nó tận dụng tăng tốc ở cấp kernel và hoạt động trong suốt với ứng dụng phía trên
Trừ khi có nhiều ứng dụng cần ACL và khóa khác nhau, còn không thì mã hóa ngay trong DB là không cần thiết
So với cách mã hóa toàn bộ tệp một cách đơn giản thì tất nhiên nhìn sẽ tốt hơn, nhưng đây chỉ là mức triển khai cơ bản
Bản thân chúng ta cũng nên nhắm tới chất lượng ở mức này
So với I/O lưu trữ, chi phí mã hóa gần như miễn phí
Tôi muốn biết ngoài MotherDuck ra thì có mô hình nào vận hành DuckDB trên nền tảng đám mây cho nhiều người dùng tốt không
Tôi đang tìm một kiến trúc cho phép nhiều người cùng truy cập như DB thông thường mà vẫn giữ được các ưu điểm của DuckDB
Hiệu năng khác biệt khá lớn tùy vào việc lưu tệp
.duckdbở đâu (S3 hay EFS)Nhưng DuckLake có vẻ là lựa chọn nhiều người dùng tốt hơn
Chúng tôi đang dùng DuckLake trong sản phẩm, và để giảm suy giảm hiệu năng thì các bảng phân tích được lưu trên lớp lưu trữ nhanh như GCP Filestore
Ngay trong một catalog DuckLake cũng có thể trộn nhiều kiểu lưu trữ khác nhau nên khá linh hoạt
DuckDB đến giờ vẫn hữu ích hơn các công cụ AI mà tôi từng dùng
Tôi thích LLM, nhưng xét về hiệu quả công việc thực tế thì DuckDB giúp ích nhiều hơn hẳn
Tôi tò mò về cách xử lý lập chỉ mục của khóa
Khi tìm kiếm thì có tra cứu trên khóa đã mã hóa hay phải giải mã theo từng khối không
Có người nói “tiện ích mở rộng mã hóa của SQLite là add-on trả phí 2000 đô”, nhưng
SQLiteMultipleCiphers đã được cung cấp miễn phí từ rất lâu rồi
Ngoài ra Turso Database cũng hỗ trợ mã hóa mặc định
Có vẻ quá trình link ở mỗi ngôn ngữ đều khá rắc rối
Đây là giải pháp đã được phát triển từ năm 2009 và vận hành ổn định