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

听起来您可能想要做更多关于加密的背景知识,特别是数据库加密选项(您没有提到数据存储,但有 MySQL 和 Postgres 选项用于完全加密)。一般来说,“自己动手”几乎总是一个坏主意,不幸的是,在 mcrypt() 和 openssl_*() 函数之间,坦率地说,向新手提供的选项太多(例如同等地展示 EBC 和 CBC有效选项)。虽然此线程:https ://security.stackexchange.com/questions/18197/why-shouldnt-we-roll-our-own主要是在谈论创建“新颖”密码原语的徒劳,但该原则也适用于幼稚的尝试在实施应用程序级和数据库级加密方面也是如此。

实际上,您可能必须处理的最具挑战性的事情是密码/密钥管理问题。下面的代码将所有责任放在客户端(发件人)身上 - 除非您保存提交的密码(这会破坏整个目的),如果用户忘记或将来无法提供他们的密码,加密数据在数据库中将无法恢复。(而且,是的,如果你真的想走牦牛剃须之路,可以选择多密钥信封加密)。

如果您将密钥/密码存储在服务器端,那么充其量只是在对手的路径上设置一个小障碍:如果她能够设法读取您的密钥文件,她就可以检索数据。但最糟糕的是,通过在本地保存密码,您会给用户一种虚假的安全感,如果这是财务、健康或其他受保护的信息,您和您的组织将承担该责任。

最后,这里有一个成熟的库:http: //phpseclib.sourceforge.net/crypt/examples.html但在我看来,它为新手用户提供了太多选择(例如,参见代码生成器)。对于密码散列,请仔细查看此处的 phpPass 库:http ://www.openwall.com/phpass/ 。

综上所述,这里是简单的双向、相当强的加密的工作开始,具有随机生成的初始化向量和盐,以及 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

如果攻击者可以访问密码列表,他们只能看到存储的哈希值。

当然,如果 Jane 也使用相同的密码,她的哈希值也将是ED6522687- 这意味着如果您闯入任何一个帐户(通过暴力破解、社会工程等),您将可以访问这两个帐户,因为您可以看到他们的哈希匹配。

加盐是在散列之前对密码进行某些处理的地方,这对每个用户都是唯一的并且是可重复的。盐应该是可预测的,所以假设 Bob 和 Jane 的盐是随机数。

现在,如果您对 bob 的密码进行哈希处理ABCDEF123,您将获得与 Jane's 不同的哈希值ABCDEF456

请注意,这不是一个完整的解释。其他一些需要考虑的事情:

  • 在这种情况下,没有随机数之类的东西,只有密码安全的随机数——它们的随机性是多么复杂,与熵和其他有趣的东西有关。
  • 哈希计算的速度是阻碍暴力破解的一个主要因素 - 像这样的哈希算法bcrypt被设计为计算成本很高。不像(说)SHA2
  • 用户没有理由提交(甚至知道)他们的盐。

另一个通常没有得到足够重视的观察结果......你永远不应该相信你在互联网上读到的关于这样一个话题的任何东西——有太多人不完全理解(我认为自己就是其中之一)。因此,将此作为不自己做的理由,而不是如何做的指南。

于 2013-07-08T14:11:56.893 回答