用PHP存储用于向客户发送邮件的电子邮件帐户数据的最佳方式是什么


What is the best way to store e-mail accounts data used for sending mailing to customers in PHP?

我正在使用PEAR::Mail向我们的客户发送大量电子邮件。我希望能够使用不同的SMTP帐户发送这些电子邮件(因为邮件类型不同)。我们有大约6-7个账户,未来可能会有更多。它们中的每一个都有不同的密码,我们希望能够将这些密码存储在数据库中,这样它就不会被硬编码,这样您就可以使用管理员面板更容易地添加它们。

我知道我想使用加密来存储密码,但imo哈希不是这里的选项。我希望能够读取这些密码,而不仅仅是比较哈希值。

我想把加密的密码存储在数据库中,但用一些算法加密它们。这就是我的问题所在——我对此了解不多。我附上了我的加密测试代码,但我想听听你对我应该如何改进它的意见:

if (!function_exists('hex2bin')) {
    function hex2bin($data) {
        $len = strlen($data);
        return pack('H' . $len, $data);
    }
}
$key = $_GET['key'];
$text = $_GET['text'];
$encr = $_GET['encr'];
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
if ($text != null) {
    echo bin2hex(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB, $iv));
}
if ($encr != null) {
    echo mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, hex2bin($encr), MCRYPT_MODE_ECB);
}

ECB模式不安全,此模式将忽略IV。您确实应该使用CBC(MCRYPT_MODE_CBC)。

当使用CBC时,加密需要IV,解密需要相同的IV,因此您需要保留此值(但不要对所有加密/解密都使用相同的IV),生成代码示例中的随机IV是正确的。IV不需要安全存储(比加密数据更安全),将IV预处理为加密数据是标准流程。

bin2hex($iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv));

解密时,您可以剥离IV并将其传递给mcrypt_decrypt。

$cipherTextDecoded = hex2bin($encr);
$iv = substr($cipherTextDecoded, 0, $iv_size);
$cipherText = substr($cipherTextDecoded, $iv_size);
mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $cipherText, MCRYPT_MODE_CBC, $iv);

还要注意,您应该使用二进制密钥。$_GET['key']返回一个文本字符串,因为您没有对其进行十六进制解码,所以您的密钥空间被限制为所有可能的256位字符串,而不是所有256位二进制值。

此外,这在PHP中有点误导,但MCRYPT_RIJNDAEL_256中的256指的是块大小,而不是加密的强度。如果要使用256位加密,只需将256位密钥传递给mcrypt函数即可。如果这是你的目标,我会考虑使用MCRYPT_RIJNDAEL_128,这将使加密文本与AES-128兼容。如果你需要在其他系统中解密数据(我不太可能知道),那么找到AES-128的实现比Rijindael 256要容易得多。

我创建了一个类,它可以执行Syon提到的所有操作。我把它附在这里供将来参考,如果有人想使用它,请随意。

<?php
if (!function_exists('hex2bin')) {
    function hex2bin($data) {
        $len = strlen($data);
        return pack('H' . $len, $data);
    }
}
/**
 * Encipherer - Class used for encoding and decoding
 *
 * @author kelu
 * @version $Id$
 * 
 */
class Encipherer {
    private $key;
    private $iv_size;
    private $mode =         MCRYPT_MODE_CBC;
    private $algorithm =    MCRYPT_RIJNDAEL_256;
    private $rand =         MCRYPT_RAND;
    /**
     * returns singleton
     *
     * @return Encipherer
     */
    public static function Instance()
    {
        static $inst = null;
        if ($inst === null) {
            $inst = new Encipherer;
        }
        return $inst;
    }
    private function __construct($key = '') {
        $this->iv_size = mcrypt_get_iv_size($this->algorithm, $this->mode);
        $this->key = $this->key = hex2bin($key);
    }
    private function __clone()
    {
        return Encipherer::Instance();
    }
    public function setKey($key) {
        $this->key = $this->key = hex2bin($key);
    }
    public function encrypt($text) {
        $iv = mcrypt_create_iv($this->iv_size, $this->rand);
        return bin2hex($iv . mcrypt_encrypt($this->algorithm, $this->key, $text, $this->mode, $iv));
    }
    public function decrypt($text) {
        $cipherTextDecoded = hex2bin($text);
        $iv = substr($cipherTextDecoded, 0, $this->iv_size);
        $cipherText = substr($cipherTextDecoded, $this->iv_size);
        return mcrypt_decrypt($this->algorithm, $this->key, $cipherText, $this->mode, $iv);
    }
}
?>

示例用法:

<?
$enc = Encipherer::Instance();
$enc->setKey('1234qwerty');
$encrypted = $enc->encrypt('secret message');
$decrypted = $enc->decrypt($encrypted);
?>