使用PHP来encryption和解密密码的最佳方法?

可能重复:
PHP的双向encryption:我需要存储可以检索的密码

我计划在我的网站上存储我的用户的外部账户信息,也就是用户名和密码等等。我想保证信息的安全,但是我知道如果我把他们的信息散列出来,我不能检索它以备后用。

Base64是可以解密的,所以没有意义使用它。 我的想法是在用户解密之前和之后通过这种方式来打乱用户,如果你尝试解密,你会看到一些有趣的文字。 有没有一个PHP函数接受值将会使一个string的唯一争夺,并解除它后来的价值重新计算?

有什么build议么?

你不应该encryption密码,而应该使用像bcrypt这样的algorithm对它们进行哈希处理。 这个答案解释了如何在PHP中正确实现密码哈希 。 不过,这里是你将如何encryption/解密:

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

encryption:

 $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" ); 

警告 :上面的例子encryption信息,但它不authentication密文,以防止篡改。 您不应该依赖未经身份validation的encryption来安全性 ,尤其是因为所提供的代码容易受到填充Oracle攻击的影响。

也可以看看:

另外,不要只为密钥使用“密码”。 encryption密钥是随机string。


在3v4l.org演示 :

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

安全警告 :这个类是不安全的。 它使用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"; 

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

工作示例

 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); 

有一件事你应该很清楚在处理encryption时:

试图聪明,发明自己的东西通常会给你一些不安全的东西。

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

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

如果决定encryption,你应该使用一些高级的encryption库,否则你错误的。 您必须正确设置密钥设置,消息填充和完整性检查,否则您的所有encryption工作都无用。 GPGME是一个很好的select。 Mcrypt的水平太低,你可能会错误的。

安全警告 :此代码不安全 。 除了易受到select密文攻击之外,对unserialize()依赖使得它易受PHP Object Object的影响。

处理一个string/数组我使用这两个函数:

 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存储/发送一个string或数组,因为在encryption之前串行化string/数组。

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

如果您使用的是Postgres,则可以使用pgcrypto进行数据库级别的encryption。 (使search和sorting更容易)

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

脚本

  1. user-pass与md5一起存储在数据库中,用于validation每个用户login到系统。 这个用户通行证对于每个用户是不同的。
  2. 数据库中的每个用户条目在md5中都有一个用于encryption/解密数据的system-pass 。 这个系统传递对于每个用户是相同的。
  3. 每当用户被从系统中删除,所有在旧系统中encryption的数据都必须在新的系统下再次encryption,以避免安全问题。
Interesting Posts