- ตั้งแต่ DuckDB เวอร์ชัน 1.4 ได้เพิ่มฟีเจอร์ การเข้ารหัสข้อมูลที่จัดเก็บ (Data-at-Rest Encryption) ทำให้สามารถปกป้องไฟล์ฐานข้อมูลทั้งชุดด้วย การเข้ารหัสมาตรฐานที่อิง AES ได้
- อัลกอริทึมที่รองรับคือ AES-GCM-256 และ AES-CTR-256 โดย GCM จะมี แท็กยืนยันความถูกต้อง (tag) สำหรับตรวจสอบความสมบูรณ์ของข้อมูล
- การเข้ารหัสครอบคลุมทั้ง ไฟล์ฐานข้อมูล, WAL (Write-Ahead Log), และไฟล์ชั่วคราว พร้อมมี โครงสร้างแคชความปลอดภัย สำหรับการจัดการคีย์และการปกป้องหน่วยความจำ
- มีให้เลือกใช้ 2 อิมพลีเมนเทชันคือ OpenSSL และ Mbed TLS โดยเมื่อใช้ OpenSSL จะมี การเร่งความเร็วด้วยฮาร์ดแวร์ ทำให้แทบไม่มีผลกระทบด้านประสิทธิภาพ
- ไฟล์ DuckDB ที่เข้ารหัสแล้วช่วยให้ได้ทั้ง ความปลอดภัยและการพกพา พร้อมรองรับการแจกจ่ายข้อมูลอย่างปลอดภัยในสภาพแวดล้อมคลาวด์หรือ CDN
ภาพรวมการเข้ารหัส
- ตั้งแต่ DuckDB 1.4 เป็นต้นไป สามารถ เข้ารหัสแบบโปร่งใส (Transparent Encryption) ให้กับไฟล์ฐานข้อมูลทั้งชุดได้
- ใช้การเข้ารหัส AES-GCM-256 หรือ AES-CTR-256 ขณะจัดเก็บ
- AES-GCM จะคำนวณแท็กสำหรับตรวจสอบความสมบูรณ์ ส่วน AES-CTR เร็วกว่าแต่ไม่มีความสามารถในการยืนยันความถูกต้อง
- AES เป็น อัลกอริทึมการเข้ารหัสแบบกุญแจสมมาตร ที่ใช้คีย์เดียวกันทั้งการเข้ารหัสและถอดรหัส
- ใช้ IV (Initialization Vector) และ nonce เพื่อรับประกันว่าข้อความธรรมดาเดียวกันจะถูกแปลงเป็นข้อความเข้ารหัสที่ต่างกัน
- ยังไม่เป็นไปตามข้อกำหนดมาตรฐาน NIST อย่างสมบูรณ์
โครงสร้างการทำงานภายในของ DuckDB
- ส่วนหัวหลัก ของไฟล์ฐานข้อมูลยังคงเป็นข้อความธรรมดา และเก็บแฟลกที่ระบุสถานะการเข้ารหัสรวมถึง เมทาดาทาการเข้ารหัส
- เมทาดาทาประกอบด้วยตัวระบุฐานข้อมูล (salt), ข้อมูลอัลกอริทึมการเข้ารหัส และ canary ที่ถูกเข้ารหัส
- ใช้ ฟังก์ชันสืบทอดคีย์ (KDF) เพื่อแปลงคีย์ที่ผู้ใช้ป้อนให้เป็นคีย์ความปลอดภัยขนาด 32 ไบต์
- คีย์ที่สืบทอดแล้วจะถูกเก็บไว้ใน แคชความปลอดภัย และจะไม่ถูกสลับออกไปยังดิสก์
- คีย์ต้นฉบับจะถูกลบออกจากหน่วยความจำทันที
- บล็อกข้อมูลจะถูกจัดเก็บเป็นหน่วยขนาด 256KB โดยค่าเริ่มต้น และเมื่อเข้ารหัสแล้ว ส่วนหัวบล็อกจะมี nonce/IV และ แท็ก เพิ่มเข้ามา ทำให้ขยายเป็น 40 ไบต์
- checksum จะถูกเข้ารหัสแล้วจัดเก็บ
การเข้ารหัส WAL (Write-Ahead Log)
- WAL เป็นไฟล์บันทึกสำหรับการกู้คืนธุรกรรม โดยใน DuckDB จะทำ การเข้ารหัสในระดับรายการ
- แต่ละรายการจะเพิ่ม nonce และแท็กเพื่อป้องกันด้วยวิธี AES-GCM
- รายการ WAL ที่เข้ารหัสแล้วประกอบด้วย ความยาว (ข้อความธรรมดา) → nonce → checksum และข้อมูลที่เข้ารหัส → แท็ก
- ในฐานข้อมูลที่กำหนดคีย์เข้ารหัสไว้ การเข้ารหัส WAL จะถูก เปิดใช้งานอัตโนมัติ
การเข้ารหัสไฟล์ชั่วคราว
- ไฟล์ชั่วคราว ที่ถูกสร้างระหว่างงานประมวลผลขนาดใหญ่ เช่น การจัดเรียง, การ join, และ window function ก็จะถูกเข้ารหัสอัตโนมัติเช่นกัน
- จะเปิดใช้งานเมื่อเชื่อมต่อฐานข้อมูลที่เข้ารหัส หรือกำหนด
SET temp_file_encryption = true
- DuckDB จะสร้าง คีย์ชั่วคราว ภายในเอง และหากเกิดการชนกันจะไม่สามารถถอดรหัสได้
- ไฟล์ชั่วคราวจะใช้นามสกุล
.tmp หรือ .block และมีข้อมูลขนาดรวมอยู่ในส่วนหัว
- checksum ถูกละไว้เพื่อลดต้นทุนในการคำนวณ
วิธีใช้งานการเข้ารหัส
การอิมพลีเมนต์และประสิทธิภาพ
- DuckDB มีอิมพลีเมนเทชันการเข้ารหัส 2 แบบคือ Mbed TLS และ OpenSSL เพื่อลดการพึ่งพาภายนอกให้น้อยที่สุด
- Mbed TLS มีประสิทธิภาพต่ำกว่าเนื่องจากไม่ได้เปิดใช้การเร่งด้วยฮาร์ดแวร์ และหลังพบช่องโหว่ในตัวสร้างเลขสุ่มจึงได้ ปิดการทำงานฝั่งเขียน (ตั้งแต่ 1.4.1 เป็นต้นไป)
- OpenSSL ใช้ การเร่งด้วยฮาร์ดแวร์และตัวสร้างเลขสุ่มที่ปลอดภัย และจะสลับไปใช้อัตโนมัติเมื่อโหลดส่วนขยาย
httpfs
- ผลการทดสอบประสิทธิภาพ:
- คิวรี SUMMARIZE แบบไม่เข้ารหัส: 5.4 วินาที
- เข้ารหัสด้วย Mbed TLS: 6.2 วินาที
- เข้ารหัสด้วย OpenSSL: 5.4 วินาที (ไม่มีประสิทธิภาพลดลง)
- ในการทดสอบ TPC-H Power/Throughput ก็พบว่าเมื่อใช้การเข้ารหัส ความแตกต่างด้านประสิทธิภาพมีน้อยมาก
- Power@Size: 624,296 → 571,985
- Throughput@Size: 450,409 → 145,353 (ลดลงเล็กน้อยเมื่อดิสก์ I/O เพิ่มขึ้น)
บทสรุป
- ฟีเจอร์ การเข้ารหัสข้อมูลที่จัดเก็บ ของ DuckDB ช่วยปกป้องไฟล์ฐานข้อมูลทั้งชุดได้อย่างปลอดภัย
- มี การเข้ารหัสรวมถึง WAL และไฟล์ชั่วคราว จึงช่วยลดความเสี่ยงข้อมูลรั่วไหลในสภาพแวดล้อมคลาวด์
- เมื่อใช้อิมพลีเมนเทชันที่อิง OpenSSL แทบไม่มีการสูญเสียประสิทธิภาพ จึงใช้งานได้อย่างมีประสิทธิภาพในสภาพแวดล้อมจริง
- ไฟล์ DuckDB ที่เข้ารหัสแล้วเหมาะกับ การแจกจ่ายภายนอก เช่น CDN และยังคงความสามารถเดิม เช่น การจัดเก็บหลายตาราง
- ทีม DuckDB มีแผนปรับปรุงฟีเจอร์นี้เพิ่มเติมจากฟีดแบ็กของผู้ใช้ในอนาคต
1 ความคิดเห็น
ความคิดเห็นใน Hacker News
ความอ่อนไหวของ การใช้ nonce ซ้ำ ใน AES-GCM เป็นจุดที่ทำให้การนำไปใช้งานจริงค่อนข้างยาก
ในเอกสารรับรู้ประเด็นนี้อยู่ แต่ไม่ได้แชร์วิธีแก้ไว้
ใน header มี nonce 16 ไบต์แทนที่จะเป็น 12 ไบต์ และก็ไม่ได้ระบุชัดว่าไบต์ไหนเป็นค่าที่สุ่ม ทำให้งงอยู่พอสมควร ไม่แน่ใจว่าผมพลาดอะไรไปหรือเปล่า
ยังทึ่งกับผลงานของทีม DuckDB อยู่เรื่อย ๆ
ก่อนหน้านี้เคยทำโซลูชันง่าย ๆ สำหรับเข้ารหัสไฟล์ DuckDB ด้วย OpenSSL แต่ตอนรันคิวรีครั้งแรกใช้เวลา นานขึ้น 2 เท่า และกินหน่วยความจำมาก
แต่ DuckDB ใช้การเข้ารหัสระดับเพจและอาศัย AES acceleration ของ CPU เลยแทบไม่มีต้นทุนในการอ่าน/เขียนเลย
มันใช้ acceleration ระดับเคอร์เนลได้ และทำงานแบบโปร่งใสกับแอปพลิเคชันชั้นบน
ถ้าไม่ใช่กรณีที่หลายแอปต้องใช้ ACL และคีย์คนละชุดกัน การเข้ารหัสในตัว DB เองก็ดูไม่จำเป็น
ถ้าเทียบกับวิธีเข้ารหัสทั้งไฟล์แบบง่าย ๆ มันก็ดูดีกว่าเป็นธรรมดา แต่จริง ๆ แล้วนี่คือ การทำ implementation ในระดับพื้นฐาน
เราเองก็ควรตั้งเป้าคุณภาพในระดับนี้ให้ได้
เมื่อเทียบกับต้นทุนของ storage I/O แล้ว ค่าใช้จ่ายของการเข้ารหัสแทบจะฟรี
อยากรู้ว่านอกจาก MotherDuck แล้ว มีโมเดลไหนที่รัน DuckDB บนคลาวด์แบบหลายผู้ใช้ ได้ดีบ้าง
กำลังมองหาโครงสร้างที่ให้ผู้ใช้หลายคนเข้าถึงพร้อมกันได้แบบฐานข้อมูลทั่วไป แต่ยังคงข้อดีของ DuckDB ไว้
ประสิทธิภาพต่างกันมากตามตำแหน่งที่เก็บไฟล์
.duckdb(S3 vs EFS)แต่ DuckLake ดูจะเป็นตัวเลือกแบบหลายผู้เล่นที่ดีกว่า
เราใช้ DuckLake อยู่ในโปรดักต์ และเพื่อให้ประสิทธิภาพตกน้อยที่สุด ก็เก็บตารางสำหรับงานวิเคราะห์ไว้บนสตอเรจเร็ว ๆ อย่าง GCP Filestore
ภายในแค็ตตาล็อก DuckLake เดียวกันก็ผสมหลายรูปแบบสตอเรจได้ จึงยืดหยุ่นดี
DuckDB มีประโยชน์กว่าเครื่องมือ AI ทั้งหมดที่เคยใช้มาจนถึงตอนนี้
ผมชอบ LLM นะ แต่ถ้าวัดเรื่องประสิทธิภาพในการทำงานจริง DuckDB ช่วยได้มากกว่ามาก
สงสัยเรื่อง วิธีจัดการดัชนีของคีย์
เวลาค้นหา เขาค้นหาคีย์ในสภาพที่เข้ารหัสอยู่เลยหรือไม่ หรือว่าต้องถอดรหัสทีละบล็อก
มีคนพูดว่า “ส่วนขยายเข้ารหัสของ SQLite เป็นแอดออนเสียเงิน 2000 ดอลลาร์” แต่
SQLiteMultipleCiphers เปิดให้ใช้ฟรีมานานแล้ว
และ Turso Database ก็รองรับการเข้ารหัสเป็นค่าเริ่มต้น
กระบวนการลิงก์ของแต่ละภาษาดูยุ่งยากพอสมควร
เป็นโซลูชันที่พัฒนามาตั้งแต่ปี 2009 และทำงานได้เสถียร