フィールドの暗号化とクエリ可能性
項目一覧
Overview
次の Queryable Encryption に関するトピックについて学びます。
暗号化されたフィールドでクエリを有効にする際の考慮事項。
暗号化のフィールドを指定する方法。
暗号化されたフィールドをクエリ可能にするように構成する方法。
クエリのタイプと暗号化されたフィールドで使用できるタイプ。
暗号化されたフィールドでクエリパフォーマンスを最適化する方法。
クエリを有効にする際の考慮事項
Queryable Encryption を使用する場合、暗号化されたフィールドをクエリ可能にするかどうかを選択できます。 暗号化されたフィールドをクエリする必要がある CRUD 操作を実行する必要がない場合は、そのフィールドでクエリを有効にする必要がない場合があります。 You can still retrieve the entire document by querying other fields that are queryable or not encrypted.
暗号化されたフィールドをクエリ可能にすると、Queryable Encryption は暗号化されたフィールドごとにインデックスを作成します。これにより、そのフィールドの書込み操作が長くなる可能性があります。 書込み (write) 操作によってインデックス付きフィールドがアップデートされると、MongoDB は関連するインデックスもアップデートします。
暗号化されたコレクションを作成すると、MongoDB は2 つのメタデータのコレクションを作成し、ストレージ容量の必要量を増やします。
暗号化するフィールドを指定する
Queryable Encryption では、JSON 暗号化スキーマを使用して、MongoDB ドキュメント内のどのフィールドを自動的に暗号化するフィールドを指定します。 暗号化スキーマは、どのフィールドが暗号化され、それらのフィールドでどのクエリが使用できるかを定義します。
重要
暗号化には、 _id
フィールドを除く任意のフィールドを指定できます。
暗号化とクエリのフィールドを指定するには、次のプロパティを含む暗号化スキーマを作成します。
キー名 | タイプ | 必須 |
---|---|---|
path | 文字列 | 必須 |
bsonType | 文字列 | 必須 |
keyId | バイナリ | 必須。 各フィールドのキー値を指定します。 注意
|
queries | オブジェクト | 任意。 フィールドをクエリ可能にするために含めます。 |
例
この例では、暗号化スキーマの作成方法を示します。
個人を特定できる情報(PII)、クレジットカード情報、機密性の高い医療情報が含まれている次のドキュメントを検討してみましょう。
{ "firstName": "Jon", "lastName": "Snow", "patientId": 12345187, "address": "123 Cherry Ave", "medications": [ "Adderall", "Lipitor" ], "patientInfo": { "ssn": "921-12-1234", "billing": { "type": "visa", "number": "1234-1234-1234-1234" } } }
PII と機密医療情報を安全に保つには、暗号化スキーマを作成し、それらのフィールドを自動暗号化用に構成します。 事前に、暗号化されたフィールドごとに一意のキーを生成する必要があります。 例:
const encryptedFieldsObject = { fields: [ { path: "patientId", keyId: "<unique data encryption key>", bsonType: "int" }, { path: "patientInfo.ssn", keyId: "<unique data encryption key>", bsonType: "string" }, { path: "medications", keyId: "<unique data encryption key>", bsonType: "array" }, { path: "patientInfo.billing", keyId: "<unique data encryption key>", bsonType: "object" } ] }
クライアントでAutoEncryptionSettings
を構成し、 createEncryptedCollection()
ヘルパー メソッドを使用してコレクションを作成します。
クエリのフィールドの設定
フィールドをクエリ可能にするには、フィールドにqueries
プロパティを含めます。 これにより、承認されたクライアントは、それらのフィールドに対して読み取りおよび書込みクエリを発行できるようになります。 queries
プロパティを省略すると、クライアントはフィールドをクエリできなくなります。
例
queries
前のサンプル スキーマに プロパティを追加して、 フィールドとpatientId
patientInfo.ssn
フィールドをクエリ可能にします。
const encryptedFieldsObject = { fields: [ { path: "patientId", bsonType: "int", queries: { queryType: "equality" } }, { path: "patientInfo.ssn", bsonType: "string", queries: { queryType: "equality" } }, { path: "medications", bsonType: "array" }, { path: "patientInfo.billing", bsonType: "object" }, ] }
競合
同じフィールドと値のペアを連続して複数のドキュメントに挿入するなどの同時書込み操作では、競合(競合)が発生し、操作が遅延する可能性があります。
Queryable Encryption を使用すると、MongoDB は内部カウンターを使用して、暗号化されたコレクション内の各フィールドと値のペアの発生を追跡します。 競合係数は、配列のようにこのカウンターを分割します。 これにより、 insert
、 update
、またはfindAndModify
を使用して、同じフィールドと値のペアが連続して含まれる暗号化されたフィールドを追加または変更するときに、カウンターの増加に関する問題を最小限に抑えられます。 contention = 0
は、インデックス0に 1 つの要素を含む配列を作成します。 contention = 4
はインデックス0 - 4に5要素を含む配列を作成します。 MongoDB は、挿入中にランダムな配列要素を増加させます。
設定されていない場合、 contention
はデフォルトで8
になり、ほとんどのワークロードで高パフォーマンスが提供されます。 コンテンツが大きいと、濃度の低いフィールドで挿入およびアップデート操作のパフォーマンスは向上しますが、検索パフォーマンスは低下します。
競合係数の調整
オプションで、クエリ可能なフィールドにcontention
プロパティを含めて、競合係数のデフォルト値8
を変更できます。 競合係数を変更する前に、次の点を考慮してください。
フィールドで同時書込み操作が頻繁に実行される場合にのみ、デフォルト値8
より大きいcontention
を増やすことを検討してください。 競合値が高いと、挿入およびアップデート操作が優先される代わりに検索パフォーマンスが低下するため、ほとんど更新されることのないフィールドの競合係数が高い場合の利点は制約を超える可能性はありません。
フィールドが頻繁にクエリされるが、ほとんど書込まれない場合は、 contention
を減らすことを検討してください。 この場合、書込みおよび更新のパフォーマンスよりも検索パフォーマンスの方が優先されます。
以下の式を使用して、フィールドの競合係数を計算できます。
ω
は、 30ミリ秒などの短時間の フィールドでの同時書込み (write) 操作の数です。 不明な場合は、サーバーの仮想コアの数を使用できます。valinserts
は、メタデータ圧縮を最後に実行して以降に挿入された一意のフィールドと値のペアの数です。ω
✅はω/valinserts
であり、最も近い整数に切り上げられます。 1000の最近の値である100操作のワークロードの場合、100/1000 = 0.1
は1
に切り上げられます。
妥当な競合係数cf
は、次の式の結果を最も近い正の整数に切り捨てた値です。
(ω
✅ · (ω
✅ − 1)) / 0.2
たとえば、 30ミリ秒以内にフィールドで100の同時書込み操作がある場合、 ω = 100
になります。 そのフィールドに50の最近の一意の値がある場合、 ω
✅ = 100/50 = 2
になります。 これによりcf = (2·1)/0.2 = 10
が返されます。
警告
フィールドと値のペアの頻度(濃度)など、データ自体のプロパティに競合係数を設定しないでください。 競合係数はワークロードに基づいてのみ設定します。
ω = 100
とvalinserts = 1000
が、 ω
✅ =
100/1000 = 0.1 ≈ 1
とcf = (1·0)/0.2 = 0 ≈ 1
になる場合を考えてみましょう。 値の20は非常に頻繁に表示されるため、代わりにcontention = 3
を設定します。 複数のデータベース スナップショットにアクセスする攻撃者は、 設定が高いほどフィールドと値のペアが頻繁にあることを推測できます。 この場合、 contention
を設定せずにデフォルトを8
に設定すると、攻撃者はその情報を保持できなくなります。
競合とその暗号化への影響に関する詳細な情報については、MongoDB の Queryable Encryptionに関するドキュメントの「セクション9 : ガイドライン」を参照してください。
クエリ タイプ
暗号化されたフィールド オブジェクトのqueries
オプションにクエリタイプを渡すと、フィールドに許可されたクエリタイプが設定されます。 サポートされているクエリタイプを使用して、暗号化されていないフィールドまたは暗号化されたフィールドをクエリすると、暗号化されたデータが返され、クライアントで復号化されます。
Queryable Encryption は現在、 none
とequality
クエリタイプをサポートしています。 クエリタイプが指定されていない場合、デフォルトはnone
になります。 クエリタイプがnone
の場合、フィールドは暗号化されますが、クライアントはそのフィールドをクエリできません。
equality
クエリタイプは次の式をサポートしています。
注意
暗号化されたフィールドをnull
または正規表現と比較するクエリでは、サポートされているクエリ演算子であってもエラーが発生します。
Queryable Encryption equality
クエリでは、暗号化されたフィールドが次のBSONタイプのいずれかと比較される場合、フィールドに対する読み取りまたは書込み操作はサポートされていません。
double
decimal128
object
array
クライアントとサーバー スキーマ
MongoDB は、コレクション内の特定のフィールドの暗号化を強制するために、スキーマ検証を使用することをサポートしています。 自動 Queryable Encryption を使用するクライアントは、データベース接続構成に応じて特定の動作をします。
接続
encryptedFieldsMap
オブジェクトに指定されたコレクションのキーが含まれている場合、クライアントは、リモート スキーマを使用するのではなく、そのオブジェクトを使用して自動 Queryable Encryption を実行します。 ローカル ルールは、少なくとも、リモート スキーマが暗号化が必要とマークするフィールドを暗号化する必要があります。接続
encryptedFieldsMap
オブジェクトに指定されたコレクションのキーが含まれていない場合、クライアントはコレクションのサーバー側リモート スキーマをダウンロードし、それを使用して自動 Queryable Encryption を実行します。重要
動作に関する考慮事項
クライアントが指定コレクションの暗号化スキーマを持っていない場合、次の状況が発生します。
クライアントは、サーバーが自動 Queryable Encryption に関する有効なスキーマを持っていることを信頼します。
クライアントはリモート スキーマを使用して自動 Queryable Encryption のみを実行します。 クライアントは、スキーマで指定された他の検証ルールを強制しません。
自動 Queryable Encryption の詳細については、次のリソースを参照してください。
Queryable Encryption の有効化
コレクションを作成する前に、Queryable Encryption を有効にします。 コレクションの作成後に Queryable Encryption を有効にしても、そのコレクション内のドキュメントのフィールドは暗号化されません。 次の 2 つの方法のいずれかの方法で、フィールドで Queryable Encryption を有効にできます。
アプリケーションがコレクションを作成するために使用するクライアントに、
encryptedFieldsObject
定数で表される暗号化スキーマを渡します。
const client = new MongoClient(uri, { autoEncryption: { keyVaultNameSpace: "<your keyvault namespace>", kmsProviders: "<your kms provider>", extraOptions: { cryptSharedLibPath: "<path to Automatic Encryption Shared Library>" }, encryptedFieldsMap: { "<databaseName.collectionName>": { encryptedFieldsObject } } } ... await client.db("<database name>").createCollection("<collection name>"); }
autoEncryption
構成オプションの詳細については、「 Queryable Encryption の MongoClient オプション 」のセクションを参照してください。
暗号化されたフィールド オブジェクトを
createCollection()
に渡して新しいコレクションを作成します。
await encryptedDB.createCollection("<collection name>", { encryptedFields: encryptedFieldsObject });
Tip
コレクションを作成するとき、およびコレクションにアクセスするためのクライアントを作成するときに暗号化されたフィールドを指定します。 これにより、サーバーのセキュリティが侵害された場合でも、クライアントを介して情報は暗号化されます。
重要
挿入操作で暗黙的にコレクションを作成するのではなく、明示的にコレクションを作成します。 createCollection()
を使用してコレクションを作成すると、MongoDB は暗号化されたフィールドにインデックスを作成します。 このインデックスがないと、暗号化されたフィールドに対するクエリの実行が遅くなる可能性があります。