私はまだ暗号化の初心者であり、次の問題を解決するためのベストプラクティスを知りたいです。
ユーザーの電子メールアドレスをデータベース内で(保存して)暗号化する必要があるという要件を持つアプリケーションを作成しています。電子メールアドレスはユーザーの識別子でもあるため、データベース内の一意のフィールドである必要があります。
新しいユーザーがサインアップすると、電子メールの暗号化された値が以前に暗号化されたすべての値と比較され、重複がないかチェックされます。
AES-256などの対称アルゴリズムを使用すると、次のことが保証されます。
必要なときにプレーンテキストにアクセスできるようにする必要があるため、一方向のハッシュとソルトを使用したくありません。
どんな助けやアドバイスも大歓迎です。
AESのようなブロック暗号は、ハッシュがソルトを使用するのとほぼ同じ方法で初期化ベクトル(IV)を使用します。そのため、同じデータを繰り返し暗号化しても同じ暗号テキストは生成されません(これは良いことです)。もちろん、すべての暗号化操作で同じIVを使用できます。これは、暗号化の数学的強さを完全に弱めるため、ひどい、恐ろしい考えですが、ここでは、教育上の理由からオプションとして含めます。
あなたの質問に答える:
1。 2つの異なるメール間で衝突が発生することはありません
IVが固定されている場合:いいえ、衝突は発生しません。論理的には、2つの異なる入力文字列が同じ暗号テキストになる場合、それらをどのように復号化して2つの異なる出力に戻すことができますか?
固有のIVがある場合:はい、衝突が発生する可能性があります。ブロックサイズが大きい(したがってIVが大きい)場合、この確率は非常に小さくなります。安全のために、暗号化してdbの衝突をチェックし、衝突がある場合は新しいランダムIVで暗号化できます。
2。同じ電子メールのうちの2つが異なる暗号文(確定的)になることはありません
IVを固定して:正解です。 IVは、AESでのランダム性(非決定性)の唯一のソースです。固定IVでは、同じ入力で常に同じ出力が得られます。
一意のIVを使用:いいえ、2つの異なるIVで暗号化された同じ入力は、2つの異なる出力を提供します。
あなたのポイント#2は、暗号化(および安全なハッシュ)の基本的な目標の1つである正反対のことを要求するため、少し困惑します Ciphertext Indistinguishability ;攻撃者が2つの暗号文メッセージを見た場合、それらが同じ平文メッセージから来たかどうかを知る方法がないという考え。
Niel McGuiganがコメントで述べたように、あなたの脅威モデルは何ですか?または別の言い方をすると、データを保護しようとしているものに対して?外部の攻撃者がデータベースとそれをクラックしようとしていますか?詮索好きな目を持つ内部データベース管理者?ログファイルを難読化しようとしていますか?これらの問題には標準的な解決策がありますが、すべて異なります。
ですから、これは宿題のようですが、仕事の割り当てかもしれません。私は両方を満たす方法で答えるようにします。まず、データベースと保存されたデータの暗号化に関するいくつかの一般的な考え。 FWIW、私は以前、大規模なデータベースベンダーで働いていたため、列とテーブルの暗号化機能を構築した開発者に助言しました。
データベースに保存されたデータの暗号化に関する課題は、正反対の目標です。単純に保存された古いデータでは、主キー(列のデータは一意である必要があります)または外部キー(結合)の場合、インデックス(高速検索用)が必要になることがよくあります。暗号化されたデータでは、プレーンテキストデータのプロパティはそれほど重要ではありませんが、暗号化テキストが誤ってプレーンテキストに関する情報を明らかにしないように注意してください。ここでも、一意性プロパティは実際には機能しませんが、暗号化テキストは一意にすることができます。さらに重要なことは、暗号化テキストの一致(暗号化テキストが可逆暗号化であるか、不可逆ハッシュであるかに関係なく)は非要件であり、つまり一致させたくない.
正反対を参照してください? 検索可能vs。情報漏えいなし。検索可能とは、そこにインデックスがあること、つまり、ソートされていること、つまり、データのプロパティに関する情報があることを意味します。暗号化テキストの並べ替えは役に立たないので、プレーンテキストでインデックスを並べ替えたいのですが、それで情報が漏洩します!つまり、基本的に、私たちが言っていることは、あなたはこの1つで本当に小川を登っているということです。あなたの例では、電子メールアドレスは一意であり(プライマリキーのように、データベースで検索可能)、しかも盗難の場合は情報を提供しない(安全な方法で暗号化する)必要があります。
そうは言っても、保存されたデータの暗号化の問題を解決したいので、どうすればよいですか?
(1)ネイティブデータベース暗号化または(2)アプリケーションレベル暗号化の2つのソリューションがあります。
ネイティブデータベース暗号化では、データベース自体が暗号化を実行し、データを暗号化してディスクに保存し、データとともにウォレットとIVにさまざまなキーを保持し、データを取得できるユーザーと取得できないユーザーにアクセス制御を提供します。また、データ列が主キーである場合、または列にインデックスがある場合に、インデックスを暗号化します。ある意味では、これは称賛されたアクセス制御スキームにすぎません。ただし、データが暗号化された形式で(保存されて)保存されるという要件を満たしています。もちろん、これは暗号化機能がプロプライエタリデータベースに組み込まれているか、誰かがオープンソースデータベースにコーディングしたことを意味します。
アプリケーションレベルの暗号化では、アプリ開発者がデータを暗号化してからデータベースに格納します。マイクはこのモデルでいくつかの選択肢を概説した素晴らしい仕事をしたと思います。ここでの最大の課題は、主キー(列に対して一意)にもしたいデータの暗号化を処理する方法であることを繰り返します。データを暗号化するproper(つまり安全な)方法はプレーンテキストごとに一意のIVを生成するため、すべての暗号化テキストの電子メールアドレスをスキャンして復号化してから、ユニークなメール。これは、運用の観点からは非常に良い状況ではありません(実行時の動作が非常に悪い)。
前提:暗号化する必要がある一部のデータは、データベース列でも一意である必要があります。そのデータを「メールアドレス」と呼びましょう。
各プレーンテキストに一意のIVを追加して、電子メールアドレスを適切に暗号化することをお勧めします。つまり、メールアドレス列をインデックスまたは主キーにすることはできません。まず、IVを暗号化テキストとは別の列に格納すると、平文が衝突していなくても、暗号化テキストが衝突する(等しくなる)可能性が非常に低くなります。これは非常に小さいですが、常に正確性を保つためにコーディングする必要があるため、主キーはありません。次に、cryptテキストのインデックスはとにかく役に立たない。 IVが行ごとに異なる場合、列に対して意味のある検索または結合を実行できないため、アプリケーションレベルの暗号化されたデータ列にインデックスを付けることはできません。
テーブルの行数(一意のユーザー/電子メールアドレスの数)によっては、そのデータを使用して何かをすることは恐ろしいことです。触れるたびに、何をしているかに応じて、平均でデータの50%または100%を復号化する必要があります。データベースに高度な機能(仮想テーブル、それらを構築できるストアドプロシージャ、内部の暗号化APIなど)がある場合、データベースに大きな負担をかけることができます。これは、正直なところ、最善の策です。 Oracleは DBMS_CRYPTO PL/SQLパッケージを持っているので(私が作成しました)、そうですが、Oracleはこの問題の解決を支援します。いいえ、私はもうその会社で働いていませんし、その株も所有していません。申し訳ありませんが、これがオラクルのセールスピッチになるという意味ではありません。
これらの高度なデータベース機能にアクセスできないとしましょう。次に何をしますか?これはすべて、ユーザーデータへの攻撃を許可せずに、電子メールアドレスに関する有用な情報を公開する必要があるためです。ここで、あなたの決定は、ユーザー人口の大きさに依存します。
小さい場合は、IVを使用してすべてを暗号化し、すべてを復号化して一致させます。動作速度はそれほど高くなく、追加の開発作業はそれだけの価値はありません。これが宿題の場合は、それが最善の策です。
ユーザーの数が十分に多く、テーブル全体の解読が顕著になる場合でも、すべてを一意のIVで暗号化しますが、電子メールをハッシュする2番目のインデックス付きの列を提供します。現在、このハッシュは通常の暗号ハッシュではありません。実際、そのようなことは何も必要ありません。かなりの量の(ただし多すぎない)衝突のあるハッシュアルゴリズムが必要です。衝突はあなたの友達です。
可能なアルゴリズムは次のとおりです。
E = Email Address
Choose N s.t. 2^(N+3) <= NUM_USERS < 2^(N+4), N>=0)
H(E) = (Sum each ASCII value of E)%(2^N)
H(E)は、電子メールアドレスが均一に分布していると仮定すると、大規模なデータセットに対して平均12程度の衝突を引き起こします。H(E) 2番目の列でインデックスを付けると、プレーンテキストのメールアドレスと一致する可能性のある候補のメールアドレスをすばやく見つけることができ、他のほとんどのメールアドレスは無視されます。ユーザーがレベルを超えるとジャンプします。レベルを下回ったときにもやり直す必要があります。このプロセスにヒステリシスを追加して、ユーザーが頻繁に追加/削除する場合にハッシュ列のやり直しを回避する必要があります。
この設計には情報漏えいがあり、電子メールアドレスを推測して、それらがハッシュ列と一致するかどうかを確認できます。暗号化されていないその他のデータ(州または年齢フィールドなど)により、攻撃者はユーザーが実際に誰であるかを三角測量できる可能性があります。それは完璧ではありません。ただし、10 ^ 6人のユーザーがいる場合は、問題を解決する必要があります。これは、情報を漏洩することを意味します。
また、これではメールアドレスでの並べ替えはできません(アルファベット順の並べ替えはできません)。データ構造クラスの真のハッシュテーブルのように機能します。