全部产品
Search
文档中心

ApsaraDB for MongoDB:Gunakan fitur Queryable Encryption di MongoDB 7.0

更新时间:Jun 27, 2025

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.

Catatan

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 encryptedFieldsMap tidak 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 perintah findAndModify dibatasi.

  • 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 jsonSchema ditentukan ketika koleksi terenkripsi dibuat, kata kunci encrypt tidak dapat disertakan.

  • Tampilan, koleksi time series, dan koleksi capped tidak didukung.

  • Indeks TTL atau indeks unik tidak didukung.

  • jsonSchema tidak 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 _id tidak 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.

  1. Instal Node.js dan npm.

    curl -fsSL https://rpm.nodesource.com/setup_lts.x | sudo bash -
    sudo yum install nodejs
    
    node -v
    npm -v
  2. Instal Node.js driver resmi untuk MongoDB.

    mkdir node_quickstart
    cd node_quickstart
    npm init -y
    npm install mongodb@6.6
  3. Instal 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 libmongocrypt
  4. Instal paket mongodb-client-encryption yang menjadi dependensi Node.js driver.

    sudo yum groupinstall 'Development Tools'
    npm install mongodb-client-encryption
  5. Instal 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}
  6. 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

Catatan

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;"
  1. Buat kunci master pelanggan (CMK).

    Catatan

    Contoh 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.txt sistem 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/urandom di mongo shell untuk menghasilkan CMK 96-byte.

    echo $(head -c 96 /dev/urandom | base64 | tr -d '\n')
  2. 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, local digunakan.

    • uri: URI MongoDB. URI MongoDB dapat ditentukan oleh variabel lingkungan MONGODB_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 variabel keyVaultDatabaseName atau keyVaultCollectionName.

    • encryptedDatabaseName: nama database yang menyimpan data terenkripsi.

    • encryptedCollectionName: nama koleksi yang menyimpan data terenkripsi.

  3. 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();
  4. Buat koleksi terenkripsi.

    1. Peroleh CMK yang telah dibuat dan tentukan penyedia KMS.

      const localMasterKey = fs.readFileSync("./customer-master-key.txt");
      kmsProviders = {local: {key: localMasterKey}};
    2. Buat DEK.

      Catatan

      Sebelum melakukan langkah ini, pastikan bahwa pengguna yang ditentukan dalam variabel uri memiliki izin dbAdmin pada database encryption._keyVault dan medicalRecords.

      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"],
      });
    3. 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",
            },
          ],
        },
      };
    4. 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();
    5. Buat koleksi terenkripsi.

      const newEncDB = encClient.db(encryptedDatabaseName);
      await newEncDB.dropDatabase();
      await newEncDB.createCollection(encryptedCollectionName);
  5. Buat MongoClient yang digunakan untuk mengenkripsi operasi baca dan tulis.

    1. Tentukan koleksi yang menyimpan DEK yang telah dibuat.

      const eDB = "encryption";
      const eKV = "__keyVault";
      const keyVaultNamespace = `${eDB}.${eKV}`;
      const secretDB = "medicalRecords";
      const secretCollection = "patients";
    2. Tentukan CMK yang telah dibuat.

      Penting

      Jangan 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,
        },
      };
    3. Peroleh DEK yang telah dibuat.

      Catatan

      Nama 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" });
    4. 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();
    5. Buat objek ClientEncryption.

      const encryption = new ClientEncryption(unencryptedClient, {
        keyVaultNamespace,
        kmsProviders,
      });
  6. 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,
    });
  7. 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.image

  8. Gunakan klien yang berisi opsi terenkripsi untuk mengakses bidang terenkripsi. Jika tidak, bidang terenkripsi tidak dapat diakses.

    Gunakan klien unencryptedClient yang tidak terenkripsi untuk query tingkat bidang.

    console.log(await unencryptedClient.db(secretDB).collection(secretCollection).findOne());

    Gambar berikut menunjukkan hasil query sampel.image

    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.image

Referensi