双向加密:我需要存储可以检索的密码

时间:2011-02-23 10:48:00

标签: php security encryption passwords

我正在创建一个存储密码的应用程序,用户可以检索和查看密码。密码用于硬件设备,因此检查哈希是不可能的。

我需要知道的是:

  1. 如何在PHP中加密和解密密码?

  2. 使用?

  3. 加密密码最安全的算法是什么?
  4. 我在哪里存储私钥?

  5. 不是存储私钥,而是要求用户在需要密码解密时输入私钥是一个好主意吗? (可以信任此应用程序的用户)

  6. 密码被窃取和解密的方式有哪些?我需要注意什么?

8 个答案:

答案 0 :(得分:207)

答案 1 :(得分:14)

如何在PHP中加密和解密密码? 通过实现许多加密算法之一。 (或使用众多图书馆之一)

加密密码最安全的算法是什么? 有许多不同的算法,其中没有一个是100%安全的。但其中许多都足够安全,可用于商业甚至军事目的

我在哪里存储私钥? 如果您决定实施公钥 - 加密算法(例如RSA),则不存储私钥。用户有私钥。你的系统有公钥,可以存储在你想要的任何地方。

要求用户在需要密码解密时输入私钥,最好不要存储私钥吗? (可以信任此应用程序的用户) 好吧,如果你的用户能够记住那些可疑的长素数 - 是的,为什么不呢。但通常你需要提出一个允许用户在某处存储密钥的系统。

密码以何种方式被盗和解密?我需要注意什么? 这取决于所使用的算法。但是,请务必确保不向用户发送未加密的密码。在客户端加密/解密,或使用https(或用户其他加密方法来保护服务器和客户端之间的连接)。

但是,如果您只需要以加密方式存储密码,我建议您使用简单的XOR密码。该算法的主要问题是它可以通过频率分析轻松破解。但是,由于密码不是通过长段英文文本制作的,我认为你不应该担心它。 XOR Cipher的第二个问题是,如果您有加密和解密形式的消息,您可以轻松找到加密的密码。同样,在您的情况下不是一个大问题,因为它只会影响已经被其他方式泄露的用户。

答案 2 :(得分:12)

  1. 你所使用的PHP函数是Mcrypt(http://www.php.net/manual/en/intro.mcrypt.php)。
  2. 本例中略微编辑了手册中的示例):

    <?php
    $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $key = "This is a very secret key";
    $pass = "PasswordHere";
    echo strlen($pass) . "\n";
    
    $crypttext = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $pass, MCRYPT_MODE_ECB, $iv);
    echo strlen($crypttext) . "\n";
    ?>
    

    您可以使用mcrypt_decrypt来解密密码。

    1. 最好的algorithm相当主观 - 问5个人,得到5个答案。就个人而言,如果默认(Blowfish)对你不够好,你可能会有更大的问题!

    2. 鉴于PHP需要加密 - 不确定您是否可以在任何地方隐藏它 - 欢迎对此发表评论。当然,标准的PHP最佳编码实践也适用!

    3. 鉴于加密密钥无论如何都会在您的代码中,不确定您将获得什么,提供其他应用程序是安全的。

    4. 显然,如果加密密码和加密密钥被盗,那么游戏就结束了。

    5. 我会把一个骑手放在我的答案上 - 我不是PHP加密专家,但是,我认为我所回答的是标准做法 - 我欢迎其他人可能有的评论。

答案 3 :(得分:6)

许多用户建议使用mcrypt ...这是正确的,但我更进一步,以便轻松存储和传输(因为有时加密的值可能使他们难以使用卷曲等其他技术发送,或者json)。

使用mcrypt成功加密后,通过base64_encode运行它,然后将其转换为十六进制代码。一旦使用十六进制代码,就可以通过多种方式进行传输。

$td = mcrypt_module_open('tripledes', '', 'ecb', '');
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
$key = substr("SUPERSECRETKEY",0,mcrypt_enc_get_key_size($td));
mcrypt_generic_init($td, $key, $iv);
$encrypted = mcrypt_generic($td, $unencrypted);
$encrypted = $ua."||||".$iv;
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
$encrypted = base64_encode($encrypted);
$encrypted = array_shift(unpack('H*', $encrypted));

另一方面:

$encrypted = pack('H*', $encrypted);
$encrypted = base64_decode($encrypted);
list($encrypted,$iv) = explode("||||",$encrypted,2);
$td = mcrypt_module_open('tripledes', '', 'ecb', '');
$key = substr("SUPERSECRETKEY",0,mcrypt_enc_get_key_size($td));
mcrypt_generic_init($td, $key, $iv);
$unencrypted = mdecrypt_generic($td, $encrypted);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);

答案 4 :(得分:5)

如果您希望能够在没有交互的情况下设置用户密码,我建议使用公钥加密(这对于重置和共享密码非常方便)。

公钥

  1. OpenSSL扩展程序,特别是openssl_public_encryptopenssl_private_decrypt
  2. 这是直接的RSA,假设您的密码适合密钥大小 - 填充,否则您需要一个对称层
  3. 为每个用户存储两个密钥,私钥的密码是他们的应用程序密码
  4. 对称

    1. Mcrypt扩展名
    2. AES-256可能是一个安全的赌注,但这可能是一个SO问题本身
    3. 你没有 - 这将是他们的申请密码
    4. 两个

      4。是的 - 用户每次都必须输入他们的应用程序密码,但将其存储在会话中会引发其他问题

      5

      • 如果有人窃取了应用程序数据,它就像对称密码一样安全(对于公钥方案,它用于保护带有密码的私钥。)
      • 您的应用程序绝对只能通过SSL访问,最好使用客户端证书。
      • 考虑添加第二个身份验证因素,每个会话只使用一次,例如通过短信发送的令牌。

答案 5 :(得分:2)

我试过这样的事情,但请注意我不是密码学家,也不是我对php或任何编程语言的深入了解。这只是一个想法。我的想法是将key存储在某个文件中或database(或手动输入),其中(位置)无法轻易预测(当然,任何事情都会在某一天被解密,其概念是延长解密时间)并加密敏感信息。

$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH , MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "evenifyouaccessmydatabaseyouwillneverfindmyemail";
$text = "myemail@domain.com";
echo "Key : ".$key."<br/>";
echo "Text : ".$text . "<br/>";
echo "Md5 : ".md5($text). "<br/>";
echo "Sha1 : ".sha1($text). "<br/>";



$crypttext = mcrypt_encrypt(MCRYPT_BLOWFISH , $key, $text, MCRYPT_MODE_ECB, $iv);
echo "Crypted Data : ".$crypttext."<br>";

$base64 = base64_encode($crypttext);
echo "Encoded Data : ".$base64."<br/>";
$decode =  base64_decode($base64);


$decryptdata = mcrypt_decrypt(MCRYPT_BLOWFISH , $key, $crypttext, MCRYPT_MODE_ECB, $iv);

echo "Decoded Data : ".ereg_replace("?", null ,  $decryptdata); 
//event if i add '?' to the sting to the text it works, I don't know why.

请注意,这只是一个概念。对此代码的任何改进都会非常明显。

答案 6 :(得分:2)

  

密码用于硬件设备,因此检查哈希是不可能的

嗯?我不明白。你只是说密码必须是可以恢复的吗?

正如其他人所说,mcrypt扩展提供了对大量加密功能的访问 - 但是你邀请你的用户将所有的鸡蛋放在一个篮子里 - 一个可能是攻击者的目标 - 如果你不这样做甚至知道如何开始解决问题然后你正在给你的用户造成伤害。您无法理解如何保护数据。

大多数安全漏洞的出现不是因为底层算法存在缺陷或不安全 - 而是因为在应用程序代码中使用算法的方式存在问题。

话虽如此,建立一个相当安全的系统可能

如果您要求用户创建另一个(特定)用户可读的安全邮件,则应该只考虑非对称加密。原因是它的计算成本很高。如果您只想为用户提供输入和检索自己数据的存储库,则对称加密就足够了。

但是,如果您将用于解密邮件的密钥存储在与加密邮件相同的位置(或存储加密邮件的位置),则系统不安全。使用相同的令牌来验证用户和解密密钥(或者在不对称加密的情况下,使用令牌作为私钥密码短语)。由于您需要将令牌存储在至少暂时进行解密的服务器上,您可能需要考虑使用不可搜索的会话存储基板,或者将令牌直接传递给与会话相关联的守护程序,该守护程序将存储令牌在内存中并按需执行消息解密。

答案 7 :(得分:1)

使用password_hashpassword_verify

<?php
/**
 * In this case, we want to increase the default cost for BCRYPT to 12.
 * Note that we also switched to BCRYPT, which will always be 60 characters.
 */
$options = [
    'cost' => 12,
];
echo password_hash("rasmuslerdorf", PASSWORD_BCRYPT, $options)."\n";
?>

并解密:

<?php
// See the password_hash() example to see where this came from.
$hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';

if (password_verify('rasmuslerdorf', $hash)) {
    echo 'Password is valid!';
} else {
    echo 'Invalid password.';
}
?>