MongoDB 7.0 menyediakan fitur Queryable Encryption untuk skenario yang memerlukan keamanan database lebih tinggi. Topik ini menjelaskan cara menggunakan fitur tersebut.
Informasi latar belakang
Fitur enkripsi data transparan dan enkripsi disk yang disediakan oleh ApsaraDB for MongoDB adalah solusi enkripsi saat diam. Fitur-fitur ini berfungsi untuk tujuan berikut:
Perlindungan Data: Melindungi data pada disk dari akses tidak sah. Bahkan jika pengguna jahat memiliki akses fisik ke HDD atau SSD tempat data disimpan, mereka tidak dapat mengakses data yang tidak terenkripsi.
Pencegahan Kebocoran: Jika perangkat penyimpanan dicuri atau hilang, seperti dalam insiden keamanan di pusat data atau ketika laptop hilang, enkripsi memastikan bahwa data sensitif tidak dapat diakses oleh pengguna tidak sah.
Persyaratan Kepatuhan: Beberapa standar industri dan regulasi mengharuskan perusahaan untuk mengenkripsi data sensitif, termasuk informasi pribadi pengguna dan informasi keuangan. Solusi enkripsi saat diam membantu perusahaan memenuhi persyaratan regulasi.
File cadangan instance ApsaraDB for MongoDB dengan TDE atau enkripsi disk diaktifkan akan dienkripsi.
Jika Anda menggunakan solusi enkripsi saat diam, data yang dibaca ke dalam memori tetap dalam teks biasa. Untuk sepenuhnya melindungi data Anda, kami menyarankan menerapkan langkah-langkah keamanan tambahan seperti enkripsi jaringan (misalnya Secure Sockets Layer (SSL) atau Transport Layer Security (TLS)), kontrol akses database, audit, dan pemantauan. Untuk menghilangkan risiko akses oleh personel O&M internal Alibaba Cloud ke instance Elastic Compute Service (ECS) yang menjadi host layanan database Anda, Alibaba Cloud menyediakan otorisasi pelanggan dan audit paksa guna mencegah risiko keamanan.
Untuk kebutuhan keamanan database yang lebih tinggi dan metode enkripsi tambahan, Anda dapat menggunakan fitur Queryable Encryption yang dirilis resmi di MongoDB 7.0.
Pengenalan
Versi pratinjau fitur Queryable Encryption dirilis di MongoDB 6.0, dan versi resminya tersedia di MongoDB 7.0.
Fitur Queryable Encryption memungkinkan data tetap terenkripsi hingga mencapai klien. Permintaan dikirim ke server bersama dengan kunci enkripsi yang dikelola oleh Key Management Service (KMS). Kemudian, data di-query dan dikembalikan dalam bentuk ciphertext di server. Setelah data dikembalikan ke klien, data didekripsi menggunakan kunci dan ditampilkan dalam teks biasa.
Fitur Queryable Encryption menyediakan fitur-fitur berikut:
Mengenkripsi data sensitif dari klien dan hanya mengizinkan klien mendapatkan kunci enkripsi.
Mengenkripsi data selama siklus hidup data secara keseluruhan, termasuk transmisi, penyimpanan, penggunaan, audit, dan pencadangan.
Mengizinkan klien menjalankan query ekspresif pada data terenkripsi, termasuk kesetaraan, rentang, awalan, akhiran, dan query substring.
Meningkatkan kinerja perlindungan privasi data. Hanya pengguna berwenang yang dapat mengakses aplikasi di server dan menggunakan kunci enkripsi untuk melihat data dalam teks biasa.
Mempermudah pengembangan aplikasi yang melibatkan data sensitif. Pengembang dapat langsung menggunakan kemampuan enkripsi komprehensif yang disertakan dengan database untuk memastikan keamanan dan kepatuhan.
Mengurangi kekhawatiran keamanan bagi pengguna Alibaba Cloud yang ingin menyimpan data sensitif di ApsaraDB for MongoDB.
Fitur yang dirilis oleh MongoDB Community Edition sedikit berbeda dari Enterprise Edition (Atlas). MongoDB Community Edition tidak mendukung enkripsi otomatis.
Untuk informasi lebih lanjut tentang versi driver dan versi database terenkripsi, lihat Kompatibilitas Queryable Encryption.
Batasan
Hasil dari perintah diagnostik dan log query pada koleksi terenkripsi diedit lebih lanjut atau disembunyikan, yang mengganggu analisis masalah:
Perintah yang berlaku untuk koleksi terenkripsi, seperti
aggregate, count, find, insert, update, and delete, tidak dicatat dalam log query lambat dan profiler.Hasil dari perintah diagnostik, seperti
collStats, currentOp, top, or $planCacheStats, diedit lebih lanjut dan beberapa bidang dalam hasilnya disembunyikan.
Kompetisi dan konflik di antara bidang terenkripsi dapat meningkatkan penundaan tulis. Bidang-bidang selesai ketika kontensi default adalah 8.
Koleksi metadata yang melebihi ukuran 1 GB harus dikompresi secara manual. Untuk informasi lebih lanjut, lihat Kompaksi Koleksi Metadata.
Objek
encryptedFieldsMaptidak dapat diubah, termasuk bidang query dalam objek.Fitur Queryable Encryption hanya didukung oleh instance set replika atau kluster sharded.
Data dengan Queryable Encryption diaktifkan pada node sekunder tidak dapat dibaca.
Dokumen tidak dapat diperbarui secara batch dengan menjalankan perintah
updateMany or bulkWrite, dan parameter dalam perintahfindAndModifydibatasi.Semantik upsert tidak didukung. Ketika upsert dipicu, bidang terenkripsi tidak dimasukkan.
Fitur Client-Side Field Level Encryption (CSFLE) tidak dapat diaktifkan untuk koleksi bersamaan dengan fitur Queryable Encryption, dan koleksi dengan CSFLE diaktifkan atau koleksi tanpa enkripsi tidak dapat diubah menjadi koleksi dengan Queryable Encryption diaktifkan.
Fitur Queryable Encryption hanya dapat diaktifkan untuk koleksi kosong baru.
Koleksi yang berisi bidang terenkripsi tidak dapat diganti namanya. Bidang-bidang tersebut tidak dapat diganti namanya dengan menjalankan perintah
$rename.Jika
jsonSchemaditentukan ketika koleksi terenkripsi dibuat, kata kunciencrypttidak dapat disertakan.Tampilan, koleksi time series, dan koleksi capped tidak didukung.
Indeks TTL atau indeks unik tidak didukung.
jsonSchematidak dapat dinonaktifkan.Koleksi harus dihapus menggunakan MongoClient dengan Queryable Encryption diaktifkan. Jika tidak, metadata tetap ada.
Fitur Queryable Encryption tidak mendukung collation. Collation menghalangi pengurutan normal untuk bidang terenkripsi.
Bidang
_idtidak dapat ditentukan sebagai bidang terenkripsi.Sejumlah perintah dan operator terbatas didukung oleh fitur Queryable Encryption. Untuk informasi lebih lanjut, lihat Operasi yang Didukung untuk Queryable Encryption.
Persiapan
Contoh berikut menggunakan instance ECS sebagai klien verifikasi. Jika lingkungan pengujian Anda berisi dependensi terkait, Anda dapat melewati langkah-langkah yang sesuai. Mongosh hanya mendukung enkripsi otomatis, dan MongoDB Community Edition hanya mendukung enkripsi eksplisit. Bagian ini menggunakan Node.js driver untuk verifikasi.
Instal Node.js dan npm.
curl -fsSL https://rpm.nodesource.com/setup_lts.x | sudo bash - sudo yum install nodejs node -v npm -vInstal Node.js driver resmi untuk MongoDB.
mkdir node_quickstart cd node_quickstart npm init -y npm install mongodb@6.6Instal pustaka libmongocrypt.
vi /etc/yum.repos.d/libmongocrypt.repo // Masukkan konten berikut dalam file. [libmongocrypt] name=libmongocrypt repository baseurl=https://libmongocrypt.s3.amazonaws.com/yum/redhat/8/libmongocrypt/1.8/x86_64 gpgcheck=1 enabled=1 gpgkey=https://pgp.mongodb.com/libmongocrypt.asc // instal sudo yum install -y libmongocryptInstal paket mongodb-client-encryption yang menjadi dependensi Node.js driver.
sudo yum groupinstall 'Development Tools' npm install mongodb-client-encryptionInstal mongosh dan konfigurasikan variabel lingkungan MONGODB_URI.
wget https://repo.mongodb.org/yum/redhat/8/mongodb-org/7.0/x86_64/RPMS/mongodb-mongosh-2.2.5.x86_64.rpm yum install -y ./mongodb-mongosh-2.2.5.x86_64.rpm export MONGODB_URI="mongodb://root:xxxxxx@dds-2zef23cef14b4f142.mongodb.pre.rds.aliyuncs.com:3717,dds-2zef23cef14b4f141.mongodb.pre.rds.aliyuncs.com:3717/admin?replicaSet=mgset-855706" // Uji konektivitas. mongosh ${MONGODB_URI}Peroleh pustaka bersama terenkripsi otomatis.
Pilih klien yang sesuai dengan mesin dan versi distribusi Anda di Pusat Unduhan, dan pilih paket crypt_shared. Untuk informasi lebih lanjut, lihat Unduh MongoDB Enterprise Server.
// Dekompresi direktori lokal untuk mendapatkan file lib/mongo_crypt_v1.so. tar -xzvf mongo_crypt_shared_v1-linux-x86_64-enterprise-rhel80-7.0.9.tgz
Prosedur
MongoDB Community Edition tidak mendukung enkripsi otomatis. Oleh karena itu, bagian ini menjelaskan proses enkripsi eksplisit.
Masuk ke lingkungan Read-Eval-Print Loop (REPL) Node.js dan lakukan langkah-langkah berikut:
node -i -e "const MongoClient = require('mongodb').MongoClient; const ClientEncryption = require('mongodb').ClientEncryption;"Buat kunci master pelanggan (CMK).
CatatanContoh berikut menunjukkan konfigurasi sampel dari penyedia KMS lokal. Kami menyarankan Anda untuk tidak menggunakan konfigurasi ini di lingkungan produksi.
Buat CMK 96-byte dan simpan CMK dalam file
customer-master-key.txtsistem file lokal.const fs = require("fs"); const crypto = require("crypto"); try { fs.writeFileSync("customer-master-key.txt", crypto.randomBytes(96)); } catch (err) { console.error(err); }Dalam contoh ini, Node.js digunakan untuk memanggil string acak guna menghasilkan CMK 96-byte. Anda juga dapat menggunakan
/dev/urandomdi mongo shell untuk menghasilkan CMK 96-byte.echo $(head -c 96 /dev/urandom | base64 | tr -d '\n')Inisialisasi variabel.
// Nama penyedia KMS harus salah satu dari berikut: "aws", "gcp", "azure", "kmip" atau "local" const kmsProviderName = "local"; const uri = process.env.MONGODB_URI; const keyVaultDatabaseName = "encryption"; const keyVaultCollectionName = "__keyVault"; const keyVaultNamespace = "encryption.__keyVault"; const encryptedDatabaseName = "medicalRecords"; const encryptedCollectionName = "patients";Dalam kode sampel sebelumnya, variabel berikut diinisialisasi:
kmsProviderName: nama penyedia KMS. Dalam contoh ini,localdigunakan.uri: URI MongoDB. URI MongoDB dapat ditentukan oleh variabel lingkunganMONGODB_URI. Anda juga dapat menentukan URI MongoDB.keyVaultDatabaseName: nama database yang menyimpan kunci enkripsi data (DEK).keyVaultCollectionName: nama koleksi yang menyimpan DEK. Koleksi tersebut harus berbeda dari koleksi reguler.keyVaultNamespace: sama dengan variabelkeyVaultDatabaseNameataukeyVaultCollectionName.encryptedDatabaseName: nama database yang menyimpan data terenkripsi.encryptedCollectionName: nama koleksi yang menyimpan data terenkripsi.
Buat indeks unik pada koleksi yang menyimpan DEK.
const keyVaultClient = new MongoClient(uri); await keyVaultClient.connect(); const keyVaultDB = keyVaultClient.db(keyVaultDatabaseName); // Hapus database dengan nama yang sama dengan database yang menyimpan DEK untuk mencegah kelebihan data. await keyVaultDB.dropDatabase(); const keyVaultColl = keyVaultDB.collection(keyVaultCollectionName); await keyVaultColl.createIndex( { keyAltNames: 1 }, { unique: true, partialFilterExpression: { keyAltNames: { $exists: true } }, } ); // periksa dua kali await keyVaultColl.indexes();Buat koleksi terenkripsi.
Peroleh CMK yang telah dibuat dan tentukan penyedia KMS.
const localMasterKey = fs.readFileSync("./customer-master-key.txt"); kmsProviders = {local: {key: localMasterKey}};Buat DEK.
CatatanSebelum melakukan langkah ini, pastikan bahwa pengguna yang ditentukan dalam variabel
urimemiliki izin dbAdmin pada databaseencryption._keyVaultdanmedicalRecords.const clientEnc = new ClientEncryption(keyVaultClient, { keyVaultNamespace: keyVaultNamespace, kmsProviders: kmsProviders, }); const dek1 = await clientEnc.createDataKey(kmsProviderName, { keyAltNames: ["dataKey1"], }); const dek2 = await clientEnc.createDataKey(kmsProviderName, { keyAltNames: ["dataKey2"], });Tentukan bidang yang akan dienkripsi dan konfigurasikan DEK yang telah dibuat.
const encryptedFieldsMap = { [`${encryptedDatabaseName}.${encryptedCollectionName}`]: { fields: [ { keyId: dek1, path: "patientId", bsonType: "int", queries: { queryType: "equality" }, }, { keyId: dek2, path: "medications", bsonType: "array", }, ], }, };Tentukan pustaka bersama terenkripsi otomatis dan buat MongoClient.
const extraOptions = {cryptSharedLibPath: "/root/lib/mongo_crypt_v1.so"}; const encClient = new MongoClient(uri, { autoEncryption: { keyVaultNamespace, kmsProviders, extraOptions, encryptedFieldsMap, }, }); await encClient.connect();Buat koleksi terenkripsi.
const newEncDB = encClient.db(encryptedDatabaseName); await newEncDB.dropDatabase(); await newEncDB.createCollection(encryptedCollectionName);
Buat MongoClient yang digunakan untuk mengenkripsi operasi baca dan tulis.
Tentukan koleksi yang menyimpan DEK yang telah dibuat.
const eDB = "encryption"; const eKV = "__keyVault"; const keyVaultNamespace = `${eDB}.${eKV}`; const secretDB = "medicalRecords"; const secretCollection = "patients";Tentukan CMK yang telah dibuat.
PentingJangan gunakan file kunci lokal di lingkungan produksi.
const fs = require("fs"); const path = "./customer-master-key.txt"; const localMasterKey = fs.readFileSync(path); const kmsProviders = { local: { key: localMasterKey, }, };Peroleh DEK yang telah dibuat.
CatatanNama DEK harus sama dengan nama DEK yang dibuat dalam sublangkah sekunder Langkah 4.
const uri = process.env.MONGODB_URI;; const unencryptedClient = new MongoClient(uri); await unencryptedClient.connect(); const keyVaultClient = unencryptedClient.db(eDB).collection(eKV); const dek1 = await keyVaultClient.findOne({ keyAltNames: "dataKey1" }); const dek2 = await keyVaultClient.findOne({ keyAltNames: "dataKey2" });Tentukan pustaka bersama terenkripsi otomatis dan buat MongoClient.
const extraOptions = { cryptSharedLibPath: "/root/lib/mongo_crypt_v1.so", }; const encryptedClient = new MongoClient(uri, { autoEncryption: { kmsProviders: kmsProviders, keyVaultNamespace: keyVaultNamespace, bypassQueryAnalysis: true, keyVaultClient: unencryptedClient, extraOptions: extraOptions, }, }); await encryptedClient.connect();Buat objek ClientEncryption.
const encryption = new ClientEncryption(unencryptedClient, { keyVaultNamespace, kmsProviders, });
Sisipkan dokumen yang berisi bidang terenkripsi ke dalam koleksi terenkripsi yang telah dibuat.
const patientId = 12345678; const medications = ["Atorvastatin", "Levothyroxine"]; const indexedInsertPayload = await encryption.encrypt(patientId, { algorithm: "Indexed", keyId: dek1._id, contentionFactor: 1, }); const unindexedInsertPayload = await encryption.encrypt(medications, { algorithm: "Unindexed", keyId: dek2._id, }); const encryptedColl = encryptedClient.db(secretDB).collection(secretCollection); await encryptedColl.insertOne({ firstName: "Jon", patientId: indexedInsertPayload, medications: unindexedInsertPayload, });Lakukan query tingkat bidang pada koleksi terenkripsi yang telah dibuat.
const findPayload = await encryption.encrypt(patientId, { algorithm: "Indexed", keyId: dek1._id, queryType: "equality", contentionFactor: 1, }); console.log(await encryptedColl.findOne({ patientId: findPayload }));Gambar berikut menunjukkan hasil query sampel.

Gunakan klien yang berisi opsi terenkripsi untuk mengakses bidang terenkripsi. Jika tidak, bidang terenkripsi tidak dapat diakses.
Gunakan klien
unencryptedClientyang tidak terenkripsi untuk query tingkat bidang.console.log(await unencryptedClient.db(secretDB).collection(secretCollection).findOne());Gambar berikut menunjukkan hasil query sampel.

Anda juga dapat menggunakan mongosh untuk mengakses bidang terenkripsi secara eksternal. Ini mensimulasikan akses ke koleksi terenkripsi yang dibuat tanpa kunci klien.
// Buka sesi terminal lain dan gunakan mongosh untuk terhubung ke URI MongoDB. mongosh ${MONGODB_URI} db.getSiblingDB("medicalRecords").patients.findOne()Gambar berikut menunjukkan hasil sampel.
