218

可能重复:
PHP 2 路加密:我需要存储可以检索的密码

我计划在我的网站上为我的用户存储外国帐户信息,即 rapidshare 用户名和密码等...我想保证信息的安全,但我知道如果我对他们的信息进行哈希处理,我将无法检索它以供以后使用.

Base64 是可解密的,所以直接使用它是没有意义的。我的想法是打乱用户并在它以这种方式进行base64化之前和之后通过,即使在你解密它之后,如果你尝试解密,你会得到一些看起来很有趣的文本。是否有一个接受值的 php 函数,这些值将对字符串进行唯一的加扰,并在稍后重新输入值时对其进行解扰?

有什么建议么?

4

8 回答 8

303

您不应加密密码,而应使用 bcrypt 之类的算法对密码进行哈希处理。这个答案解释了如何在 PHP 中正确实现密码散列不过,这里是你将如何加密/解密:

$key = 'password to (en/de)crypt';
$string = ' string to be encrypted '; // note the spaces

加密:

$iv = mcrypt_create_iv(
    mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC),
    MCRYPT_DEV_URANDOM
);

$encrypted = base64_encode(
    $iv .
    mcrypt_encrypt(
        MCRYPT_RIJNDAEL_128,
        hash('sha256', $key, true),
        $string,
        MCRYPT_MODE_CBC,
        $iv
    )
);

解密:

$data = base64_decode($encrypted);
$iv = substr($data, 0, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC));

$decrypted = rtrim(
    mcrypt_decrypt(
        MCRYPT_RIJNDAEL_128,
        hash('sha256', $key, true),
        substr($data, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC)),
        MCRYPT_MODE_CBC,
        $iv
    ),
    "\0"
);

警告:上面的例子加密了信息,但它没有验证密文以防止篡改。您不应该依赖未经身份验证的加密来确保安全,尤其是因为所提供的代码容易受到填充预言机攻击。

也可以看看:

此外,不要只使用“密码”作为加密密钥。加密密钥是随机字符串。


3v4l.org 上的演示

echo 'Encrypted:' . "\n";
var_dump($encrypted); // "m1DSXVlAKJnLm7k3WrVd51omGL/05JJrPluBonO9W+9ohkNuw8rWdJW6NeLNc688="

echo "\n";

echo 'Decrypted:' . "\n";
var_dump($decrypted); // " string to be encrypted "
于 2009-08-17T16:49:56.117 回答
36

安全警告:此类不安全。它使用Rijndael256-ECB,这在语义上并不安全。仅仅因为“它有效”并不意味着“它是安全的”。此外,由于未使用适当的填充,它会在之后去除尾随空间。

最近发现了这门课,它就像做梦一样!

class Encryption {
    var $skey = "yourSecretKey"; // you can change it

    public  function safe_b64encode($string) {
        $data = base64_encode($string);
        $data = str_replace(array('+','/','='),array('-','_',''),$data);
        return $data;
    }

    public function safe_b64decode($string) {
        $data = str_replace(array('-','_'),array('+','/'),$string);
        $mod4 = strlen($data) % 4;
        if ($mod4) {
            $data .= substr('====', $mod4);
        }
        return base64_decode($data);
    }

    public  function encode($value){ 
        if(!$value){return false;}
        $text = $value;
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->skey, $text, MCRYPT_MODE_ECB, $iv);
        return trim($this->safe_b64encode($crypttext)); 
    }

    public function decode($value){
        if(!$value){return false;}
        $crypttext = $this->safe_b64decode($value); 
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        $decrypttext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->skey, $crypttext, MCRYPT_MODE_ECB, $iv);
        return trim($decrypttext);
    }
}

并称之为:

$str = "My secret String";

$converter = new Encryption;
$encoded = $converter->encode($str );
$decoded = $converter->decode($encoded);    

echo "$encoded<p>$decoded";
于 2011-02-02T14:48:00.383 回答
18

安全警告:此代码不安全。

工作示例

define('SALT', 'whateveryouwant'); 

function encrypt($text) 
{ 
    return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, SALT, $text, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)))); 
} 

function decrypt($text) 
{ 
    return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, SALT, base64_decode($text), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))); 
} 

$encryptedmessage = encrypt("your message"); 
echo decrypt($encryptedmessage); 
于 2010-11-22T10:51:10.857 回答
12

处理加密时应该非常注意的一件事:

试图变得聪明并发明自己的东西通常会给你带来不安全感。

您可能最好使用PHP 附带的加密扩展之一。

于 2009-08-17T16:50:07.817 回答
3

安全警告:此代码不安全。除了容易受到选择密文攻击之外,它的依赖unserialize()使其容易受到 PHP 对象注入的攻击。

要处理字符串/数组,我使用以下两个函数:

function encryptStringArray ($stringArray, $key = "Your secret salt thingie") {
 $s = strtr(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), serialize($stringArray), MCRYPT_MODE_CBC, md5(md5($key)))), '+/=', '-_,');
 return $s;
}

function decryptStringArray ($stringArray, $key = "Your secret salt thingie") {
 $s = unserialize(rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode(strtr($stringArray, '-_,', '+/=')), MCRYPT_MODE_CBC, md5(md5($key))), "\0"));
 return $s;
}

它很灵活,因为您可以通过 URL 存储/发送字符串或数组,因为字符串/数组在加密之前是序列化的。

于 2010-10-04T12:08:58.830 回答
2

这只会给你边际保护。如果攻击者可以在您的应用程序中运行任意代码,他们可以以与您的应用程序完全相同的方式获取密码。如果您将密钥存储在文件中并使用它在通往数据库的途中加密并在出路时解密,您仍然可以获得一些 SQL 注入攻击和错误放置的数据库备份的保护。但是你应该使用 bindparams 来完全避免 SQL 注入的问题。

如果决定加密,你应该为此使用一些高级加密库,否则你弄错的。您必须正确设置密钥设置、消息填充和完整性检查,否则您的所有加密工作都无济于事。GPGME就是一个很好的选择。Mcrypt 级别太低,你可能会弄错。

于 2009-08-17T16:53:45.970 回答
1

查看 mycrypt():http ://us.php.net/manual/en/book.mcrypt.php

如果您使用的是 postgres,则可以使用 pgcrypto 进行数据库级加密。(使搜索和排序更容易)

于 2009-08-17T16:50:59.890 回答
0

即使您有权访问代码,对数据库中的数据进行加密/解密的最佳方法是使用 2 次不同的通行证user-pass,每个用户的私人密码 ( ) 和所有用户的私人密码 ( system-pass)。

设想

  1. user-pass与 md5 一起存储在数据库中,用于验证每个用户是否登录系统。这个用户通行证对于每个用户都是不同的。
  2. 数据库中的每个用户条目在 md5 中都有system-pass用于数据的加密/解密。此系统通行证对于每个用户都是相同的。
  3. 每当用户从系统中删除时,所有在旧系统通行证下加密的数据都必须在新系统通行证下再次加密以避免安全问题。
于 2012-11-18T15:19:24.967 回答