Navigation

Client-Side Encryption

Client-Side Field Level Encryption allows administrators and developers to encrypt specific data fields in addition to other MongoDB encryption features.

Automatic Encryption and Decryption

Note

Auto encryption is an enterprise only feature.

The following example uses a local key; however, other key providers such as AWS are also an option. The data in the encryptedField field is automatically encrypted on insertion and decrypted when querying on the client side.

<?php

use MongoDB\BSON\Binary;
use MongoDB\Client;
use MongoDB\Driver\ClientEncryption;

$localKey = new Binary('<binary key data (96 bytes)>', Binary::TYPE_GENERIC);

$encryptionOpts = [
    'keyVaultNamespace' => 'encryption.__keyVault',
    'kmsProviders' => [
        'local' => ['key' => $localKey],
    ],
];

$client = new Client();
$clientEncryption = $client->createClientEncryption($encryptionOpts);

$database = $client->selectDatabase('test');
$database->dropCollection('coll'); // remove old data

// Create new key in the key vault and store its ID for later use
$keyId = $clientEncryption->createDataKey('local');

$database->createCollection('coll', [
    'validator' => [
        '$jsonSchema' => [
            'bsonType' => 'object',
            'properties' => [
                'encryptedField' => [
                    'encrypt' => [
                        'keyId' => [$keyId],
                        'bsonType' => 'string',
                        'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
                    ],
                ],
            ],
        ],
    ],
]);

$encryptedClient = new Client('mongodb://127.0.0.1', [], ['autoEncryption' => $encryptionOpts]);

$collection = $encryptedClient->selectCollection('test', 'coll');

$collection->insertOne(['encryptedField' => '123456789']);

var_dump($collection->findOne([]));

Specifying an Explicit Schema for Encryption

The following example shows how to create a new key and store it in the key vault collection. The encrypted client configures an explicit schema for encryption using the newly created key.

Note

Supplying a schemaMap provides more security than relying on JSON schemas obtained from the server. It protects against a malicious server advertising a false JSON schema, which could trick the client into sending unencrypted data that should be encrypted.

<?php

use MongoDB\BSON\Binary;
use MongoDB\Client;
use MongoDB\Driver\ClientEncryption;

$localKey = new Binary('<binary key data (96 bytes)>', Binary::TYPE_GENERIC);

$clientEncryptionOpts = [
    'keyVaultNamespace' => 'encryption.__keyVault',
    'kmsProviders' => [
        'local' => ['key' => $localKey],
    ],
];

$client = new Client();
$clientEncryption = $client->createClientEncryption($clientEncryptionOpts);

// Create new key in the key vault and store its ID for later use
$keyId = $clientEncryption->createDataKey('local');

$autoEncryptionOpts = [
    'keyVaultNamespace' => 'encryption.__keyVault',
    'kmsProviders' => [
        'local' => ['key' => $localKey],
    ],
    'schemaMap' => [
        'test.coll' => [
            'bsonType' => 'object',
            'properties' => [
                'encryptedField' => [
                    'encrypt' => [
                        'keyId' => [$keyId],
                        'bsonType' => 'string',
                        'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
                    ],
                ],
            ],
        ],
    ],
];

$encryptedClient = new Client(null, [], ['autoEncryption' => $autoEncryptionOpts]);

$collection = $encryptedClient->selectCollection('test', 'coll');
$collection->drop(); // clear old data

$collection->insertOne(['encryptedField' => '123456789']);

var_dump($collection->findOne([]));

Manually Encrypting and Decrypting Values

In the MongoDB Community Edition, you will have to manually encrypt and decrypt values before storing them in the database. The following example assumes that you have already created an encryption key in the key vault collection and explicitly encrypts and decrypts values in the document.

<?php

use MongoDB\BSON\Binary;
use MongoDB\Client;
use MongoDB\Driver\ClientEncryption;

$localKey = new Binary('<binary key data (96 bytes)>', Binary::TYPE_GENERIC);

$clientEncryptionOpts = [
    'keyVaultNamespace' => 'encryption.__keyVault',
    'kmsProviders' => [
        'local' => ['key' => $localKey],
    ],
];

$client = new Client();
$clientEncryption = $client->createClientEncryption($clientEncryptionOpts);

// Create new key in the key vault and store its ID for later use
$keyId = $clientEncryption->createDataKey('local');

$collection = $client->selectCollection('test', 'coll');
$collection->drop(); // clear old data

$encryptionOpts = [
    'keyId' => $keyId,
    'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
];
$encryptedValue = $clientEncryption->encrypt('123456789', $encryptionOpts);

$collection->insertOne(['encryptedField' => $encryptedValue]);

$document = $collection->findOne();
var_dump($clientEncryption->decrypt($document->encryptedField));

Referencing Encryption Keys by an Alternative Name

While it is possible to create an encryption key every time data is encrypted, this is not the recommended approach. Instead, you should create your encryption keys depending on your use-case, e.g. by creating a user-specific encryption key. To reference keys in your software, you can use the keyAltName attribute specified when creating the key. The following example creates an encryption key with an alternative name, which could be done when deploying the application. The software then encrypts data by referencing the key by its alternative name.

<?php

use MongoDB\BSON\Binary;
use MongoDB\Client;
use MongoDB\Driver\ClientEncryption;

$localKey = new Binary('<binary key data (96 bytes)>', Binary::TYPE_GENERIC);

$clientEncryptionOpts = [
    'keyVaultNamespace' => 'encryption.__keyVault',
    'kmsProviders' => [
        'local' => ['key' => $localKey],
    ],
];

$client = new Client();
$clientEncryption = $client->createClientEncryption($clientEncryptionOpts);

// Create an encryption key with an alternative name. This could be done when
// deploying the application
$keyId = $clientEncryption->createDataKey('local', ['keyAltNames' => ['altname']]);

$collection = $client->selectCollection('test', 'coll');
$collection->drop(); // clear old data

// Reference the encryption key we created earlier by its alternative name
$encryptionOpts = [
    'keyAltName' => 'altname',
    'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
];
$encryptedValue = $clientEncryption->encrypt('123456789', $encryptionOpts);

$collection->insertOne(['encryptedField' => $encryptedValue]);

$document = $collection->findOne();
var_dump($clientEncryption->decrypt($document->encryptedField));

Automatic Queryable Encryption

Note

Automatic queryable encryption is an enterprise only feature and requires MongoDB 6.0+.

The following example uses a local key; however, other key providers such as AWS are also an option. The data in the encryptedIndexed and encryptedUnindexed fields will be automatically encrypted on insertion and decrypted when querying on the client side. Additionally, it is possible to query on the encryptedIndexed field.

<?php

use MongoDB\BSON\Binary;
use MongoDB\Client;

$localKey = new Binary('<binary key data (96 bytes)>', Binary::TYPE_GENERIC);

$encryptionOpts = [
    'keyVaultNamespace' => 'encryption.__keyVault',
    'kmsProviders' => ['local' => ['key' => $localKey]],
];

$client = new Client();
$clientEncryption = $client->createClientEncryption($encryptionOpts);

// Create two data keys, one for each encrypted field
$dataKeyId1 = $clientEncryption->createDataKey('local');
$dataKeyId2 = $clientEncryption->createDataKey('local');

$autoEncryptionOpts = [
    'keyVaultNamespace' => 'encryption.__keyVault',
    'kmsProviders' => ['local' => ['key' => $localKey]],
    'encryptedFieldsMap' => [
        'test.coll' => [
            'fields' => [
                [
                    'path' => 'encryptedIndexed',
                    'bsonType' => 'string',
                    'keyId' => $dataKeyId1,
                    'queries' => ['queryType' => 'equality'],
                ],
                [
                    'path' => 'encryptedUnindexed',
                    'bsonType' => 'string',
                    'keyId' => $dataKeyId2,
                ],
            ],
        ],
    ],
];

$encryptedClient = new Client(null, [], ['autoEncryption' => $autoEncryptionOpts]);

/* Drop and create the collection under test. The createCollection() helper
 * will reference the client's encryptedFieldsMap and create additional,
 * internal collections automatically. */
$encryptedClient->selectDatabase('test')->dropCollection('coll');
$encryptedClient->selectDatabase('test')->createCollection('coll');
$encryptedCollection = $encryptedClient->selectCollection('test', 'coll');

/* Using a client with auto encryption, insert a document with encrypted
 * fields and assert that those fields are automatically decrypted when
 * querying. The encryptedIndexed and encryptedUnindexed fields should both
 * be strings. */
$indexedValue = 'indexedValue';
$unindexedValue = 'unindexedValue';

$encryptedCollection->insertOne([
    '_id' => 1,
    'encryptedIndexed' => $indexedValue,
    'encryptedUnindexed' => $unindexedValue,
]);

var_dump($encryptedCollection->findOne(['encryptedIndexed' => $indexedValue]));

/* Using a client without auto encryption, query for the same document and
 * assert that encrypted data is returned. The encryptedIndexed and
 * encryptedUnindexed fields should both be Binary objects. */
$unencryptedCollection = $client->selectCollection('test', 'coll');

var_dump($unencryptedCollection->findOne(['_id' => 1]));
←   Decimal128 GridFS  →