6

データベース内に暗号化されたテキスト フィールドを保持し、ソルトと承認されたパスワードに基づいてこのテキストを解読できるかどうか疑問に思っていました。

例えば:

$Salt = $_POST['Salt']; 
$Password = $Query_Results['Password'];

if ($salt == $Stored_Salt AND $Authorized_Password == $Password){
  //Perform a decryption of the stored results
   echo $Decrypted_TextField;
}

完全に暗号化/エンコードされたデータベースを作成中です。識別子の整数フィールド以外はプレーン テキストではありません。それ以外はすべて暗号化/エンコードされます。多くは一方向暗号化を使用しますが、一部のフィールドは双方向暗号化タイプを格納する必要があります。

暗号化されていないテキストをデータベースに格納できません。保存する前にすべてを暗号化する必要があります。しかし、これへのアプローチは私にとって未知のプロセスです。どこから手を付ければよいか、何かアドバイスをいただけないだろうかと考えていました。

4

2 に答える 2

9

暗号化全般、および具体的には DB 暗号化オプションについてもう少し背景を説明したいと思うかもしれません (データ ストアについては言及していませんが、完全な暗号化には MySQL と Postgres のオプションがあります)。一般に、ほとんどの場合、「独自にロールする」ことは悪い考えであり、残念なことに、mcrypt() と openssl_*() 関数の間には、率直に言って、初心者に提示されるオプションが多すぎます (EBC と CBC を同等に提示するなど)。有効なオプション)。このスレッド: https://security.stackexchange.com/questions/18197/why-shouldnt-we-roll-our-ownは主に「斬新な」暗号化プリミティブを作成することの無益さについて話していますが、原則は素朴な試みにも適用されますアプリケーションおよびデータベース レベルの暗号化の実装についても同様です。

実際問題として、対処しなければならない可能性が最も高いのは、パスワード/キー管理の問題です。以下のコードは、すべての責任をクライアント (送信者) に負わせます。また、送信されたパスワードを保存しない限り (これでは目的全体が無効になります)、ユーザーがパスワードを忘れた場合、または将来パスワードを提供できなくなった場合は、データが暗号化されます。データベース内のデータは回復不能になります。(そして、はい、本当にYak Shaving パスをたどりたい場合は、マルチキー エンベロープ暗号化のオプションがあります)。

キー/パスワードをサーバー側に保存する場合、せいぜい、敵のパスに小さな道路のバンプを配置するだけです。敵がキーファイルを読み取ることができれば、データを取得できます. しかし、最悪の場合、パスワードをローカルに保存することで、ユーザーに誤った安心感を与えることになり、これが財務、健康、またはその他の保護された情報である場合、あなたとあなたの組織はその責任の負担を負うことになります.

最後に、成熟したライブラリがここにあります: http://phpseclib.sourceforge.net/crypt/examples.htmlしかし、私の意見では、初心者ユーザーにはあまりにも多くのオプションを提供しています (たとえば、コードジェネレーター)。パスワードハッシュについては、http ://www.openwall.com/phpass/ にある phpPass ライブラリをよく見てください

そうは言っても、ランダムに生成された初期化ベクトルとソルト、および256ビットのAES対称(たとえば、非公開鍵)暗号を使用した、単純な双方向のかなり強力な暗号化の作業開始です。OSX Lion & CentOS/RedHat 6 でテスト済み。

幸運を!

//$message = escapeshellarg( $_POST['message'] );
$message = 'This is my very secret data SSN# 009-68-1234';  

// Set to some reasonable limit for DB.
// Make sure to size DB column +60 chars 
$max_msg_size = 1000;
$message = substr($message, 0, $max_msg_size);

// User's password (swap for actual form post)
//$password = escapeshellarg( $_POST['password'] );
$password = 'opensesame';

// Salt to add entropy to users' supplied passwords
// Make sure to add complexity/length requirements to users passwords!
// Note: This does not need to be kept secret
$salt = sha1(mt_rand());

// Initialization Vector, randomly generated and saved each time
// Note: This does not need to be kept secret
$iv = substr(sha1(mt_rand()), 0, 16);

echo "\n Password: $password \n Message: $message \n Salt: $salt \n IV: $iv\n";

$encrypted = openssl_encrypt(
  "$message", 'aes-256-cbc', "$salt:$password", null, $iv
);

$msg_bundle = "$salt:$iv:$encrypted";
echo " Encrypted bundle = $msg_bundle \n\n ";

// Save it... (make sure to use bind variables/prepared statements!)
/* db_write( "insert into sensitive_table encrypted_msg values (:msg_bundle)",
    $msg_bundle ); */

今それを取得します:

//  Retrieve from DB... 

//$password = escapeshellarg( $_POST['password'] );
$password = 'opensesame';

// Swap with actual db retrieval code here
//$saved_bundle = db_read( "select encrypted_msg from sensitive_table" );
$saved_bundle = $msg_bundle;

// Parse iv and encrypted string segments
$components = explode( ':', $saved_bundle );;

var_dump($components);

$salt          = $components[0];
$iv            = $components[1];
$encrypted_msg = $components[2];

$decrypted_msg = openssl_decrypt(
  "$encrypted_msg", 'aes-256-cbc', "$salt:$password", null, $iv
);

if ( $decrypted_msg === false ) {
  die("Unable to decrypt message! (check password) \n");
}

$msg = substr( $decrypted_msg, 41 );
echo "\n Decrypted message: $decrypted_msg \n";

出力例:

 Password: opensesame 
 Message: This is my very secret data SSN# 009-68-1234 

 Salt: 3f12ce187d5c5bcc3b0d5acf1e76fad8b684ff37 
 IV: 00c1d3b4c6a6f4c3 

 Encrypted bundle = 3f12ce187d5c5bcc3b0d5acf1e76fad8b684ff37:00c1d3b4c6a6f4c3:KB6k+GlM+0EHbETUgEe8Lck0nF5qBz+51wc5LtmS4XMOm0Pfyyr2PIXMVEyzs/41 

 array(3) {
  [0]=>
  string(40) "3f12ce187d5c5bcc3b0d5acf1e76fad8b684ff37"
  [1]=>
  string(16) "00c1d3b4c6a6f4c3"
  [2]=>
  string(64) "KB6k+GlM+0EHbETUgEe8Lck0nF5qBz+51wc5LtmS4XMOm0Pfyyr2PIXMVEyzs/41"
}

 Decrypted message: This is my very secret data SSN# 009-68-1234 
于 2013-06-06T04:19:14.570 に答える
2

完全な答えではありませんが、コメントするには長すぎる塩漬けの仕組みの拡張..

ソルトは、比較対象の文字列として扱われるべきではありません。ソルトは、エンド ユーザーが入力する必要はないが、そのユーザーに固有のパスワードの一部である必要があります。これは、単一の侵害されたパスワードが複数のアカウントに違反するのを防ぐために使用されます。

たとえば、Bob がパスワードを持っている非常に単純なシステムがあるとしますABCDEF

ABCDEFハッシュアルゴリズムを通過すると、(たとえば)ED6522687

攻撃者がパスワード リストにアクセスした場合、攻撃者は保存されたハッシュしか見ることができません。

もちろん、ジェーンも同じパスワードを使用している場合、彼女のハッシュも同じになりますED6522687。つまり、いずれかのアカウントに侵入した場合 (ブルート フォース、ソーシャル エンジニアリングなどによって)、両方のアカウントにアクセスできるようになります。ハッシュが一致していることがわかります。

ソルティングとは、各ユーザーに固有で反復可能なハッシングの前に、パスワードに対して何かが行われる場所です。ソルトは予測可能でなければならないので、ボブとジェーンのソルトが乱数であるとしましょう。

ここで、bob のパスワードをABCDEF123ハッシュすると、Jane のパスワードとは別のハッシュが得られますABCDEF456

これは完全な説明ではないことに注意してください。その他の考慮事項:

  • この文脈では乱数のようなものはなく、暗号学的に安全な乱数だけです - そしてそれらがどれほどランダムであるかは複雑で、エントロピーやその他の楽しいものに関連しています.
  • ブルート フォーシングを妨げる主な要因は、ハッシュの計算速度です。ハッシュ アルゴリズムbcryptは、計算コストが高くなるように設計されています。とは違う(言う)SHA2
  • ユーザーが自分のソルトを送信する (または知る) 理由はありません。

通常は十分に強調されないもう 1 つの観察結果... このようなトピックについてインターネットで読んだものは決して信用してはなりません - 不完全な理解を持っている人が多すぎます (私もその中にいると思います)。したがって、これを自分でやらない理由として捉えてください。それを行う方法のガイドではありません.

于 2013-07-08T14:11:56.893 に答える