明示的な暗号化
項目一覧
Overview
明示的な暗号化により、セキュリティをきめ細やかに制御できますが、コレクションの構成や MongoDB ドライバー のコード記述の複雑さは増します。 明示的な暗号化では、データベースで実行する各操作に対してドキュメント内のフィールドを暗号化する方法を指定し、このロジックをアプリケーション全体に含めます。
次の MongoDB 製品で明示的な暗号化が利用できます。
MongoDB Community Server
MongoDB Enterprise Advanced
MongoDB Atlas
明示的な暗号化の使用
明示的な暗号化を使用するには、CSFLE 対応のアプリケーションで次のアクションを実行する必要があります。
ClientEncryption インスタンスの作成
明示的な暗号化を使用するには、 ClientEncryption
インスタンスを作成する必要があります。 ClientEncryption
mongosh
はドライバー全体で使用される抽象化であり、Key Vault コレクションと明示的な暗号化に関係する KMS 操作をカプセル化する とします。
ClientEncryption
インスタンスを作成するには、次の情報を指定する必要があります。
キーヴォールト コレクションへのアクセス権を持つ
MongoClient
インスタンスキーヴォールト コレクションの名前空間
カスタマー マスター キーをホストするKMSプロバイダーへのアクセス用に構成された
kmsProviders
オブジェクト
その他のClientEncryption
オプションについては、CSFLE 用の MongoClient オプションを参照してください。
ClientEncryption
インスタンスの作成方法を示すコード スニペットは、このガイドの例セクションを参照してください。
読み取り操作と書込み操作におけるフィールドの暗号化
読み取りおよび書込み操作を実行する前に、アプリケーション全体で読み取りおよび書込み操作を更新し、アプリケーションがフィールドを暗号化する必要があります。
フィールドを暗号化するには、 ClientEncryption
インスタンスのencrypt
メソッドを使用します。
encrypt
メソッドの使用方法を示すコード スニペットは、このガイドの例セクションを参照してください。
手動復号化
明示的な暗号化を使用する場合、暗号化されたフィールドを手動または自動で復号化できます。
フィールドを手動で復号化するには、 ClientEncryption
インスタンスのdecrypt
メソッドを使用します。
decrypt
メソッドの使用方法を示すコード スニペットは、このガイドの例セクションを参照してください。
自動復号化
フィールドを自動的に復号化するには、 MongoClient
インスタンスを次のように構成します。
キーヴォールトコレクションを指定する
kmsProviders
オブジェクトを指定するMongoDB Community Server を使用する場合は、
bypassAutoEncryption
オプションをTrue
に設定します
注意
MongoDB Community Server で自動復号化が利用可能
自動暗号化には MongoDB Enterprise または MongoDB Atlas が必要ですが、自動復号化には次の MongoDB 製品で利用できます。
MongoDB Community Server
MongoDB Enterprise Advanced
MongoDB Atlas
自動復号化を有効にする方法を示すコード スニペットは、ご希望の言語に対応するタブを選択します。
var autoEncryptionOpts = { keyVaultNamespace: keyVaultNamespace, kmsProviders: kmsProviders, bypassAutoEncryption: true, }; var encryptedClient = Mongo( connectionString, autoEncryptionOpts );
var clientSettings = MongoClientSettings.FromConnectionString(connectionString); var autoEncryptionOptions = new AutoEncryptionOptions( keyVaultNamespace: keyVaultNamespace, kmsProviders: kmsProviders, bypassAutoEncryption: true); clientSettings.AutoEncryptionOptions = autoEncryptionOptions; var client = new MongoClient(clientSettings);
autoEncryptionOpts := options.AutoEncryption(). SetKmsProviders(kmsProviders). SetKeyVaultNamespace(KeyVaultNamespace). SetBypassAutoEncryption(true) client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(URI).SetAutoEncryptionOptions(autoEncryptionOpts)) if err != nil { return fmt.Errorf("Connect error for encrypted client: %v", err) } defer func() { _ = client.Disconnect(context.TODO()) }()
MongoClientSettings clientSettings = MongoClientSettings.builder() .applyConnectionString(new ConnectionString(connectionString)) .autoEncryptionSettings(AutoEncryptionSettings.builder() .keyVaultNamespace(keyVaultNamespace) .kmsProviders(kmsProviders).bypassAutoEncryption(true) .build()) .build(); MongoClient mongoClient = MongoClients.create(clientSettings);
const client = new MongoClient(connectionString, { monitorCommands: true, autoEncryption: { keyVaultNamespace, kmsProviders, bypassAutoEncryption: true, }, });
auto_encryption_opts = AutoEncryptionOpts( kms_providers=kms_providers, key_vault_namespace=key_vault_namespace, bypass_auto_encryption=True, ) client = MongoClient(auto_encryption_opts=auto_encryption_opts)
例
次の構造を持つドキュメントを MongoDB インスタンスに挿入するとします。
{ "name": "<name of person>", "age": <age of person>, "favorite-foods": ["<array of foods>"] }
MongoClient インスタンスの作成
この例では、同じMongoClient
インスタンスを使用して Key Vault コレクションにアクセスし、暗号化されたデータの読み取りと書込みを行います。
次のコード スニペットは、 MongoClient
インスタンスを作成する方法を示しています。
const autoEncryptionOpts = { keyVaultNamespace: keyVaultNamespace, kmsProviders: kmsProviders, }; const encryptedClient = Mongo(connectionString, autoEncryptionOpts);
var client = new MongoClient(connectionString);
client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(URI)) if err != nil { panic(fmt.Errorf("Client connect error %v", err)) }
MongoClient client = MongoClients.create(connectionString);
const client = new MongoClient(connectionString);
client = MongoClient(your_connection_uri)
ClientEncryption インスタンスの作成
次のコード スニペットは、 ClientEncryption
インスタンスを作成する方法を示しています。
const clientEncryption = encryptedClient.getClientEncryption();
var collection = client.GetDatabase(db).GetCollection<BsonDocument>(coll); var clientEncryptionOptions = new ClientEncryptionOptions( keyVaultClient: client, keyVaultNamespace: keyVaultNamespace, kmsProviders: kmsProviders); var clientEncryption = new ClientEncryption(clientEncryptionOptions);
coll := client.Database(DbName).Collection(CollName) clientEncryptionOpts := options.ClientEncryption().SetKeyVaultNamespace(KeyVaultNamespace).SetKmsProviders(kmsProviders) clientEnc, err := mongo.NewClientEncryption(client, clientEncryptionOpts) if err != nil { panic(fmt.Errorf("NewClientEncryption error %v", err)) } defer func() { _ = clientEnc.Close(context.TODO()) }()
MongoCollection<Document> collection = client.getDatabase(db).getCollection(coll); ClientEncryptionSettings clientEncryptionSettings = ClientEncryptionSettings.builder() .keyVaultMongoClientSettings(MongoClientSettings.builder() .applyConnectionString(new ConnectionString(connectionString)) .build()) .keyVaultNamespace(keyVaultNamespace) .kmsProviders(kmsProviders) .build(); ClientEncryption clientEncryption = ClientEncryptions.create(clientEncryptionSettings);
const collection = client.db(db).collection(coll); const encryption = new ClientEncryption(client, { keyVaultNamespace, kmsProviders, });
coll = client.employees.foods client_encryption = ClientEncryption( kms_providers, "encryption.___keyVault", client, coll.codec_options, )
注意
CodecOptions
MongoDB Python ドライバーでは、ドキュメントを暗号化および復号化するCodecOptions
を指定する必要があります。
暗号化および復号化されたアプリケーション データを MongoDB に書き込むMongoClient
、 Database
、またはCollection
に構成したCodecOptions
を指定します。
フィールドの暗号化と挿入
次のアルゴリズムを使用して、ドキュメントのフィールドを暗号化します。
フィールド名 | 暗号化アルゴリズム | BSON フィールド型 |
---|---|---|
name | 決定的な | 文字列 |
age | 暗号化なし | Int |
favorite-foods | ランダム | 配列 |
次のコード スニペットは、ドキュメント内のフィールドを手動で暗号化し、ドキュメントを MongoDB に挿入する方法を示しています。
注意
次の例のdataKeyId
変数は、データ暗号化キー(DEK)を参照しています。 ローカル キー プロバイダーを使用して DEK を生成する方法については、クイック スタートを参照してください。 特定のキー管理システムを使用して DEK を作成する方法については、チュートリアル を参照してください。
const encName = clientEncryption.encrypt( dataKeyId, "Greg", "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" ); const encFoods = clientEncryption.encrypt( dataKeyId, ["Cheese", "Grapes"], "AEAD_AES_256_CBC_HMAC_SHA_512-Random" ); db.getSiblingDB(database).getCollection(collection).insertOne({ name: encName, foods: encFoods, });
注意
次の例のdataKeyId
変数は、データ暗号化キー(DEK)を参照しています。 ローカル キー プロバイダーを使用して DEK を生成する方法については、クイック スタートを参照してください。 特定のキー管理システムを使用して DEK を作成する方法については、チュートリアル を参照してください。
var encryptedName = clientEncryption.Encrypt( "Greg", new EncryptOptions(algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", keyId: dataKeyId), CancellationToken.None); var encryptedFoods = clientEncryption.Encrypt( new BsonArray { "Cheese", "Grapes" }, new EncryptOptions(algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Random", keyId: dataKeyId), CancellationToken.None); collection.InsertOne(new BsonDocument { { "name", encryptedName }, { "age", 83 }, { "foods", encryptedFoods } });
注意
次の例のdataKeyId
変数は、データ暗号化キー(DEK)を参照しています。 ローカル キー プロバイダーを使用して DEK を生成する方法については、クイック スタートを参照してください。 特定のキー管理システムを使用して DEK を作成する方法については、チュートリアル を参照してください。
nameRawValueType, nameRawValueData, err := bson.MarshalValue("Greg") if err != nil { panic(err) } nameRawValue := bson.RawValue{Type: nameRawValueType, Value: nameRawValueData} nameEncryptionOpts := options.Encrypt(). SetAlgorithm("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"). SetKeyID(dataKeyId) nameEncryptedField, err := clientEnc.Encrypt( context.TODO(), nameRawValue, nameEncryptionOpts) if err != nil { panic(err) } foodsRawValueType, foodsRawValueData, err := bson.MarshalValue(bson.A{"Grapes", "Cheese"}) if err != nil { panic(err) } foodsRawValue := bson.RawValue{Type: foodsRawValueType, Value: foodsRawValueData} encryptionOpts := options.Encrypt(). SetAlgorithm("AEAD_AES_256_CBC_HMAC_SHA_512-Random"). SetKeyID(dataKeyId) foodsEncryptedField, err := clientEnc.Encrypt( context.TODO(), foodsRawValue, encryptionOpts) if err != nil { panic(err) } _, err = coll.InsertOne( context.TODO(), bson.D{{"name", nameEncryptedField}, {"foods", foodsEncryptedField}, {"age", 83}}) if err != nil { panic(err) }
注意
次の例のdataKeyId
変数は、データ暗号化キー(DEK)を参照しています。 ローカル キー プロバイダーを使用して DEK を生成する方法については、クイック スタートを参照してください。 特定のキー管理システムを使用して DEK を作成する方法については、チュートリアル を参照してください。
BsonBinary encryptedName = clientEncryption.encrypt(new BsonString("Greg"), new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic").keyId(dataKeyId)); BsonBinary encryptedFoods = clientEncryption.encrypt(new BsonArray().parse("[\"Grapes\", \"Foods\"]"), new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Random").keyId(dataKeyId)); collection.insertOne(new Document("name", encryptedName).append("foods", encryptedFoods).append("age", 83));
注意
次の例のdataKeyId
変数は、データ暗号化キー(DEK)を参照しています。 ローカル キー プロバイダーを使用して DEK を生成する方法については、クイック スタートを参照してください。 特定のキー管理システムを使用して DEK を作成する方法については、チュートリアル を参照してください。
encryptedName = await encryption.encrypt("Greg", { algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", keyId: dataKeyId, }); encryptedFoods = await encryption.encrypt(["Cheese", "Grapes"], { algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Random", keyId: dataKeyId, }); await collection.insertOne({ name: encryptedName, age: 83, foods: encryptedFoods, });
注意
次の例のdata_key_id
変数は、データ暗号化キー(DEK)を参照しています。 ローカル キー プロバイダーを使用して DEK を生成する方法については、クイック スタートを参照してください。 特定のキー管理システムを使用して DEK を作成する方法については、チュートリアル を参照してください。
encrypted_name = client_encryption.encrypt( "Greg", Algorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic, key_id=data_key_id, ) encrypted_foods = client_encryption.encrypt( ["Cheese", "Grapes"], Algorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random, key_id=data_key_id, ) coll.insert_one({"name": encrypted_name, "age": 83, "foods": encrypted_foods})
フィールドの取得と復号化
次のコード スニペットは、挿入されたドキュメントを取得し、暗号化されたフィールドを手動で復号化する方法を示しています。
const encNameQuery = clientEncryption.encrypt( dataKeyId, "Greg", "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" ); let doc = db.getSiblingDB(database).getCollection(collection).findOne({ name: encNameQuery, }); console.log(doc); doc.name = clientEncryption.decrypt(doc.name); doc.foods = clientEncryption.decrypt(doc.foods); console.log(doc);
var nameToQuery = "Greg"; var encryptedNameToQuery = clientEncryption.Encrypt( nameToQuery, new EncryptOptions(algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", keyId: dataKeyId), CancellationToken.None); var doc = collection.Find(new BsonDocument { { "name", encryptedNameToQuery } }).Single(); Console.WriteLine($"Encrypted document: {doc}"); doc["name"] = clientEncryption.Decrypt(doc["name"].AsBsonBinaryData, CancellationToken.None); doc["foods"] = clientEncryption.Decrypt(doc["foods"].AsBsonBinaryData, CancellationToken.None); Console.WriteLine($"Decrypted field: {doc}");
nameQueryRawValueType, nameQueryRawValueData, err := bson.MarshalValue("Greg") if err != nil { panic(err) } nameQueryRawValue := bson.RawValue{Type: nameQueryRawValueType, Value: nameQueryRawValueData} nameQueryEncryptionOpts := options.Encrypt(). SetAlgorithm("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"). SetKeyID(dataKeyId) nameQueryEncryptedField, err := clientEnc.Encrypt( context.TODO(), nameQueryRawValue, nameQueryEncryptionOpts) if err != nil { panic(err) } var result bson.M err = coll.FindOne( context.TODO(), bson.D{{"name", nameQueryEncryptedField}}).Decode(&result) if err != nil { if err == mongo.ErrNoDocuments { return } panic(err) } fmt.Printf("Encrypted Document: %s\n", result) nameDecrypted, err := clientEnc.Decrypt( context.TODO(), result["name"].(primitive.Binary)) foodsDecrypted, err := clientEnc.Decrypt( context.TODO(), result["foods"].(primitive.Binary)) result["foods"] = foodsDecrypted result["name"] = nameDecrypted fmt.Printf("Decrypted Document: %s\n", result)
BsonBinary encryptedNameQuery = clientEncryption.encrypt(new BsonString("Greg"), new EncryptOptions("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic").keyId(dataKeyId)); Document result = collection.find(eq("name", encryptedNameQuery)).first(); System.out.println("Encrypted Document: " + result.toJson()); result.replace("name", clientEncryption.decrypt(new BsonBinary(result.get("name", Binary.class).getData()))); result.replace("foods", clientEncryption.decrypt(new BsonBinary(result.get("foods", Binary.class).getData()))); System.out.println("Decrypted Document: " + result.toJson());
queryEncryptedName = await encryption.encrypt("Greg", { algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", keyId: dataKeyId, }); let doc = await collection.findOne({ name: queryEncryptedName }); console.log("Encrypted Document: ", doc); doc.name = encryption.decrypt(doc.name); doc.foods = encryption.decrypt(doc.foods); console.log("Decrypted document: ", doc);
name_to_query = "Greg" encrypted_name_to_query = client_encryption.encrypt( name_to_query, Algorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic, key_id=data_key_id, ) doc = client.employees.foods.find_one({"name": encrypted_name_to_query}) print("Encrypted document: %s" % (doc,)) doc["name"] = client_encryption.decrypt(doc["name"]) doc["foods"] = client_encryption.decrypt(doc["foods"]) print("Decrypted document: %s" % (doc,))
サーバー側のフィールドレベル暗号化の強制
MongoDB は、コレクション内の特定のフィールドの暗号化を強制するために、スキーマ検証を使用することをサポートしています。
特定のフィールドの暗号化を強制するように構成された MongoDB インスタンスで、明示的な暗号化メカニズムを使用してクライアント側のフィールドレベル暗号化を実行するクライアントは、MongoDB インスタンスに指定されたフィールドを暗号化する必要があります。
サーバー側で CSFLE を設定する方法については、「 CSFLE サーバー側でのスキーマ強制 」を参照してください。
詳細
キーヴォールト コレクション、データ暗号化キー、カスタマー マスター キーの詳細については、「暗号化キーとキーヴォールト 」を参照してください。
KMSプロバイダーとkmsProviders
オブジェクトの詳細については、「 KMS プロバイダー 」を参照してください。