我有一个旧的(可能是非常弱的)密码脚本,如下所示:
$hash = sha1($pass1);
function createSalt()
{
$string = md5(uniqid(rand(),true));
return substr($string,3);
}
$salt = createSalt();
$hash = sha1($salt . $hash);
如果我理解正确,盐越长,黑客为了打破散列而产生的表越大.如果我错了,请纠正我
我正在寻找一个更安全的新脚本,我正在想这样的事情会好起来的:
function createSalt()
{
$string = hash('sha256',uniqid(rand(),true));
return $string;
}
$hash = hash('sha256',$password);
$salt = createSalt();
$secret_server_hash = 'ac1d81c5f99fdfc6758f21010be4c673878079fdc8f144394030687374f185ad';
$salt2 = hash('sha256',$salt);
$hash = $salt2 . $hash . $secret_server_hash;
$hash = hash('sha512',$hash );
这更安全吗?这是否有明显的开销?
最重要的是,有没有更好的方法来确保我的数据库中的密码不能(实际)通过密码分析恢复,从而确保安全性的唯一方式是通过我自己的编码错误?
编辑:
在阅读所有答案并进一步重新解析之后,我决定继续实施保护我密码的bcrypt方法.话虽如此,出于好奇的缘故,如果我把上面的代码放在上面的代码上,再循环一遍,就可以进行十万次迭代,这样做是否能够与bcrypt的实力/安全性相似?
几个指针:
>不要对所有密码使用单一盐.每个密码使用随机生成的盐.
>不要重新创建一个未修改的哈希(碰撞问题,see my previous answer,您需要无限量的哈希输入).
>不要尝试创建自己的哈希算法或混合匹配算法到复杂的操作.
>如果卡住了破碎/不安全/快速哈希原语,请使用key strengthening.这样可以增加攻击者计算彩虹表所需的时间.例:
function strong_hash($input,$salt = null,$algo = 'sha512',$rounds = 20000) {
if($salt === null) {
$salt = crypto_random_bytes(16);
} else {
$salt = pack('H*',substr($salt,32));
}
$hash = hash($algo,$salt . $input);
for($i = 0; $i < $rounds; $i++) {
// $input is appended to $hash in order to create
// infinite input.
$hash = hash($algo,$hash . $input);
}
// Return salt and hash. To verify,simply
// passed stored hash as second parameter.
return bin2hex($salt) . $hash;
}
function crypto_random_bytes($count) {
static $randomState = null;
$bytes = '';
if(function_exists('openssl_random_pseudo_bytes') &&
(strtoupper(substr(PHP_OS,3)) !== 'WIN')) { // OpenSSL slow on Win
$bytes = openssl_random_pseudo_bytes($count);
}
if($bytes === '' && is_readable('/dev/urandom') &&
($hRand = @fopen('/dev/urandom','rb')) !== FALSE) {
$bytes = fread($hRand,$count);
fclose($hRand);
}
if(strlen($bytes) < $count) {
$bytes = '';
if($randomState === null) {
$randomState = microtime();
if(function_exists('getmypid')) {
$randomState .= getmypid();
}
}
for($i = 0; $i < $count; $i += 16) {
$randomState = md5(microtime() . $randomState);
if (PHP_VERSION >= '5') {
$bytes .= md5($randomState,true);
} else {
$bytes .= pack('H*',md5($randomState));
}
}
$bytes = substr($bytes,$count);
}
return $bytes;
}
而不是部署自己的(固有的缺陷)哈希/盐算法,为什么不使用由安全专业人士开发的?
使用bcrypt.这是为了这一点而开发的.缓慢和多轮确保攻击者必须部署大量资金和硬件才能破解您的密码.添加到每个密码盐(bcrypt REQUIRES盐),你可以确定攻击几乎是不可行的,没有可笑的资金或硬件.
Portable PHP Hashing Framework在非便携式模式下,您可以轻松地使用bcrypt生成散列.
您还可以使用crypt()函数生成输入字符串的bcrypt哈希值.如果你沿着这条路线走下去,确保每个哈希生成一个盐.
此类可以自动生成盐并根据输入验证现有散列.
class Bcrypt {
private $rounds;
public function __construct($rounds = 12) {
if(CRYPT_BLOWFISH != 1) {
throw new Exception("bcrypt not supported in this installation. See http://PHP.net/crypt");
}
$this->rounds = $rounds;
}
public function hash($input) {
$hash = crypt($input,$this->getSalt());
if(strlen($hash) > 13)
return $hash;
return false;
}
public function verify($input,$existingHash) {
$hash = crypt($input,$existingHash);
return $hash === $existingHash;
}
private function getSalt() {
$salt = sprintf('$2a$%02d$',$this->rounds);
$bytes = $this->getRandomBytes(16);
$salt .= $this->encodeBytes($bytes);
return $salt;
}
private $randomState;
private function getRandomBytes($count) {
$bytes = '';
if(function_exists('openssl_random_pseudo_bytes') &&
(strtoupper(substr(PHP_OS,3)) !== 'WIN')) { // OpenSSL slow on Win
$bytes = openssl_random_pseudo_bytes($count);
}
if($bytes === '' && is_readable('/dev/urandom') &&
($hRand = @fopen('/dev/urandom','rb')) !== FALSE) {
$bytes = fread($hRand,$count);
fclose($hRand);
}
if(strlen($bytes) < $count) {
$bytes = '';
if($this->randomState === null) {
$this->randomState = microtime();
if(function_exists('getmypid')) {
$this->randomState .= getmypid();
}
}
for($i = 0; $i < $count; $i += 16) {
$this->randomState = md5(microtime() . $this->randomState);
if (PHP_VERSION >= '5') {
$bytes .= md5($this->randomState,true);
} else {
$bytes .= pack('H*',md5($this->randomState));
}
}
$bytes = substr($bytes,$count);
}
return $bytes;
}
private function encodeBytes($input) {
return strtr(rtrim(base64_encode($input),'='),'+','.');
}
}
您可以使用此代码:
$bcrypt = new Bcrypt(15);
$hash = $bcrypt->hash('password');
$isGood = $bcrypt->verify('password',$hash);