명시적 암호화
이 페이지의 내용
개요
명시적 암호화는 MongoDB 드라이버에 대한 컬렉션을 구성하고 코드를 작성할 때 복잡성이 증가하는 대신 보안에 대한 세분화된 제어를 제공합니다. 명시적 암호화를 사용하면 데이터베이스에서 수행하는 각 작업에 대해 문서의 필드를 암호화하는 방법을 지정하고 이 로직을 애플리케이션 전체에 포함할 수 있습니다.
명시적 암호화는 다음 MongoDB 제품에서 사용할 수 있습니다.
MongoDB Community 서버
MongoDB Enterprise Advanced
MongoDB Atlas
명시적 암호화 사용
명시적 암호화를 사용하려면 CSFLE 지원 애플리케이션에서 다음 작업을 수행해야 합니다.
ClientEncryption 인스턴스 만들기
명시적 암호화를 사용하려면 ClientEncryption
인스턴스를 만들어야 합니다. ClientEncryption
는 드라이버와 mongosh
에서 사용되는 추상화로, 명시적 암호화와 관련된 키 볼트 컬렉션 및 KMS 작업을 캡슐화합니다.
ClientEncryption
인스턴스를 만들려면 다음 정보를 지정해야 합니다.
키 볼트 컬렉션에 액세스할 수 있는
MongoClient
인스턴스키 볼트 컬렉션의 네임스페이스
고객 마스터 키를 호스팅하는 KMS 제공자에 대한 액세스 권한으로 구성된
kmsProviders
객체
더 많은 ClientEncryption
옵션은 CSFLE용 MongoClient 옵션을 참조하세요.
ClientEncryption
인스턴스를 생성하는 방법을 보여주는 코드 조각을 보려면 이 가이드의 예시 섹션을 참조하세요.
읽기 및 쓰기 작업에서 필드 암호화
읽기 및 쓰기 작업을 수행하기 전에 애플리케이션이 필드를 암호화하도록 애플리케이션 전체에서 읽기 및 쓰기 작업을 업데이트해야 합니다.
필드를 암호화하려면 ClientEncryption
인스턴스의 encrypt
메서드를 사용합니다.
encrypt
메서드 사용 방법을 보여주는 코드 스니펫을 보려면 이 가이드의 예시 섹션을 참조하세요.
수동 암호 해독
명시적 암호화를 사용하는 경우 암호화된 필드를 수동으로 또는 자동으로 해독할 수 있습니다.
필드를 수동으로 해독하려면 ClientEncryption
인스턴스의 decrypt
메서드를 사용하세요.
decrypt
메서드 사용 방법을 보여주는 코드 스니펫을 보려면 이 가이드의 예시 섹션을 참조하세요.
자동 암호 해독
필드를 자동으로 해독하려면 다음과 같이 MongoClient
인스턴스를 구성합니다.
키 볼트 컬렉션 지정
kmsProviders
객체 지정MongoDB Community 서버를 사용하는 경우
bypassAutoEncryption
옵션을True
로 설정합니다.
참고
MongoDB Community 서버에서 자동 암호화 기능 사용 가능
자동 암호화에는 MongoDB Enterprise 또는 MongoDB Atlas가 필요하지만 자동 암호 해독은 다음 MongoDB 제품에서 사용할 수 있습니다.
MongoDB Community 서버
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
인스턴스를 사용하여 키 볼트 컬렉션에 액세스하고 암호화된 데이터를 읽고 씁니다.
다음 코드 스니펫은 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
을(를) 지정해야 합니다.
MongoClient
, Database
또는 Collection
에 구성한 CodecOptions
을(를) 지정합니다. 이는 암호화 및 복호화된 애플리케이션 데이터를 MongoDB에 쓰는 데 사용하게 됩니다.
필드 암호화 및 삽입
다음 알고리즘을 사용하여 문서의 필드를 암호화하려고 합니다.
필드 이름 | 암호화 알고리즘 | BSON 필드 유형 |
---|---|---|
| 결정론적 | 문자열 |
| 암호화 없음 | Int |
| 랜덤 | 배열 |
다음 코드 스니펫은 문서의 필드를 수동으로 암호화하고 문서를 MongoDB에 삽입하는 방법을 보여줍니다.
참고
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, });
참고
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 } });
참고
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) }
참고
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));
참고
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, });
참고
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 제공자를 참조하세요.