まず、MySQLデータベースに機密情報を保存するには悪い考えだと思いますなので、「DO N'T DO IT IT」などと言って応答しないでください。私は社会保障番号を保存することが絶対に不可欠なWebサイトを構築しており、DBからそのデータを取得できるようにする必要があります(ハッシュなし)。
つまり、データを暗号化/復号化するための最良の方法を調査し、暗号化を処理するカスタム関数を作成しました。これが私の暗号化関数です:
function my_data_encrypt($value){
$salt=substr(uniqid('', true), 0, 20);
$key=$salt.MY_PRIVATE_KEY;
$enc_value=base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $value, MCRYPT_MODE_CBC, md5(md5($key))));
return array("enc_value"=>$enc_value, "salt"=>$salt);
}
したがって、基本的には、saltのランダムな文字列を生成し、saltに秘密キーMY_PRIVATE_KEY
を追加します。これは、別の構成ファイルで定義されています。次に、mcrypt_encrypt
を使用してデータを暗号化し、次にbase64_encode
を使用して暗号化を安全にDBに格納します。暗号化された文字列と一意のソルトが返され、一緒にDBに保存されます。
私の考えでは、構成ファイル(DBではなく)に格納されている「秘密鍵」をミックスに投入すると、別のレベルのセキュリティが暗号化に追加され、誰かがデータベースをハッキングして暗号化された値とソルト、彼らはまだデータを復号化するために必要なすべてを持っているわけではありません。
セキュリティの専門家が私の機能をレビューして、データがハッキングされるかどうか/どのようにハッキングされるか、それを改善するために他に何かできることがあるかどうかを教えてもらえますか?
256ビットキー(Rijndael-256)を期待するブロック暗号で128ビットキー(MD5の出力、したがって128ビット)を使用しています。 PHPが適切に実装されている場合、その時点で顔に吹き付けます。ただし、 ドキュメント は、必要な長さまでキーにゼロが埋め込まれるだけであると述べています。128ビットのキーを使用する場合は、128ビットのキーを想定した暗号、つまりRijndael-128を使用することをお勧めします。
「塩」は役に立たないか、または十分に適用されていません。ソルトは弱いキーを処理するためのものであり、徹底的な検索、つまりキーがpasswordsの場合に現実的に回復できます。あなたの鍵が本物の、適切に生成された、太くてランダムな鍵である場合、ソルトは役に立ちません。一方、キーがパスワードの場合、実際には password hashing であり、より多くの労力が必要になります。
一方、 [〜#〜] iv [〜#〜] は、キーのハッシュではなく、ランダムである必要があります。ブロック暗号の適切な使用法は次のとおりです。
暗号的に強力なPRNG で生成された一意の128ビットキーを持っている(例:/dev/urandom
(Linuxシステムの場合)。
新しいメッセージを暗号化するとき、強力なPRNG(i.e. openssl_random_pseudo_bytes() を使用して新しいランダムIVを作成します。これは内部で/dev/urandom
または同等のもの)。
どんな「塩」も忘れてください。メインキーとランダムに生成されたIVで暗号化します。次に、IVを暗号化されたメッセージと一緒に保存する必要があります(SSNの場合、32バイトになります。IVには16、暗号化ブロックには16)。
次に、次の警告が適用されます。
これは暗号化です。 機密性ではなく、integrityではありません。データベースの一部を変更できる誰かが、SSNを大混乱させる可能性があります(ユーザー間で切り替えるだけの場合)。データベースの整合性は難しい問題であり、最もよく知られているソリューションは適切ではありません。それらはかなりのオーバーヘッドを意味します。
機密性は、キーが明らかにされない限り保持されます。しかし、サーバーのコンテンツへの異常に特権的な読み取りアクセス権を持つ攻撃者が想定され、サーバーは、一般的に言えば、キーを知っています。キーをデータベースから分離されたファイルに保存すると、データベースのコンテンツのみに作用する基本的なSQLインジェクション攻撃に対する保護が強化される可能性があります。ただし、someの脆弱性のみを修正したことに注意してください。
あなたにそれを壊してすみません-あなたはそれらのSSNで本当に危険なチャンスを取っています。 PCI-DSS標準に従って何かをすばやく定義しましょう:
Q:「カード会員データ」とは何ですか? A:カード会員データは、カード会員に関連する個人を特定できるデータです。これには、アカウント番号、有効期限、名前、住所、社会保障番号などがあります。保存、処理、または送信されるカード所有者に関連付けられたすべての個人識別情報も、カード所有者データと見なされます。
PCI DSSは安全な情報ストレージの標準です(できれば財務です)。ルールは厳格で、違反した場合の罰金は莫大です(1か月あたり5千ドルから10万ドル)。ただし、SSN それに従って格納できますが、ここでもガイドラインは厳格です( このドキュメントの14ページ )。したがって、現在の実装について説明する前でも、あなたが何をしているのか知っていることを強くお勧めします。
同様にいくつかのことを記録しましょう:
詳細に入りましょう。 PHP(その他の回答プロバイダー))に慣れていない人は、関数mcrypt_encrypt
をパラメーターとして使用します。
関数を少し分解してみましょう。 「WTF is this shit」の最初の明らかなポイントは、md5を使用してキーとIVを生成することです。 MD5に深刻な脆弱性があることをご存じですか?
2つ目の明らかなWTFは、暗号の選択です。 AES 512はPHPで使用できます。これにより、鍵のサイズも2倍になります。これだけでなく、塩の使用はかなり面白いです-これがIVの目的です!
3番目の明らかなWTFは、秘密鍵に定数を使用することです。この定数がスクリプトの初期化から終了まで持続することをご存知ですか?それだけでなく、ファイルの1つにクリアテキストで定義されているに違いありません。この意味は:
秘密鍵を安全に保管することを検討してください(またはさらに良いのは、そのハッシュのみを保管し、ユーザーに鍵の検証を要求して復号化することです-事実上、ユーザーに鍵を知って強制的に重要な情報を復号化させる)。
TL; DR:PCI-DSSを読んで、作成を中止し、実際に使用しているツールを理解します。まず、暗号技術の入門書をお勧めします-ブルース・シュナイアーへの異論はありますか?そうでない場合は、実用的な暗号化を選択してください(または、2001年よりも新しい版があると仮定して、より柔らかい本、Secrets&Liesを好む場合)。