更新时间:2022-12-10 13:13:51
到目前为止,盐只能帮你。如果您使用的哈希算法速度如此之快,以至于生成彩虹表几乎没有任何成本,那么您的安全性仍然会受到影响。
几点提示:
不要部署自己的(固有缺陷)哈希/盐算法,为什么不使用安全专业人员开发的一个?
使用 bcrypt 。这正是为了这一点而开发的。它的缓慢和多轮确保攻击者必须部署大量资金和硬件才能破解密码。添加到每个密码盐(bcrypt REQUIRES盐),你可以肯定,一个攻击几乎不可行,没有可笑的金额或硬件。
便携式PHP散列框架在非便携模式下允许您使用bcrypt轻松生成散列。
您也可以使用 crypt()
函数来生成输入字符串的bcrypt散列。如果你沿着这条路线走下去,确保每个散列产生一个盐。
这个类可以自动生成salt并根据输入验证现有散列。 b
$ b
class Bcrypt {
private $ rounds;
public function __construct($ rounds = 12){
if(CRYPT_BLOWFISH!= 1){
抛出新的异常(在此安装中不支持bcrypt。 /隐窝);
}
$ this-> rounds = $ rounds;
公共函数散列($ input){
$ hash = crypt($ input,$ this-> getSalt());
if(strlen($ hash)> 13)
return $ hash;
返回false;
public function verify($ input,$ existingHash){
$ hash = crypt($ input,$ existingHash);
返回$ hash === $ existingHash;
}
private function getSalt(){
$ salt = sprintf('$ 2a $%02d $',$ this-> rounds);
$ bytes = $ this-> getRandomBytes(16);
$ salt。= $ this-> encodeBytes($ bytes);
返回$ salt;
}
private $ randomState;
private function getRandomBytes($ count){
$ bytes ='';
$ b $ if(function_exists('openssl_random_pseudo_bytes')&&
(strtoupper(substr(PHP_OS,0,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();
$ b $($ i = 0; $ i $ 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,0,$ count);
}
返回$ bytes;
$ b $ private函数encodeBytes($ input){
return strtr(rtrim(base64_encode($ input),'='),'+','。');
你可以这样使用这段代码:
$ bcrypt = new Bcrypt(15);
$ hash = $ bcrypt-> hash('password');
$ isGood = $ bcrypt-> verify('password',$ hash);
I have been reading up on password hashing, but all the forums I read are full of posts from people debating theory behind it that I don't really understand.
I have an old (and presumably extremely weak) password script that reads like this: $hash = sha1($pass1);
function createSalt()
{
$string = md5(uniqid(rand(), true));
return substr($string, 0, 3);
}
$salt = createSalt();
$hash = sha1($salt . $hash);
If I understand correctly, the longer the salt, the larger the table the hacker has to generate in order to break the hash. Please correct me if I am wrong.
I am looking to write a new script that is more secure, and I am thinking that something like this would be okay:
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 );
Is this more secure? Does this have a noticeable amount of overhead?
Most importantly, is there some better way to make sure that the passwords in my database cannot be (realistically) recovered by cryptanalysis, thus ensuring that the only way security will be compromised is through my own error in coding?
Upon reading all of your answers and further reasearching, I have decided to go ahead and implement the bcrypt method of protecting my passwords. That being said, for curiosity's sake, if I were to take my above code and put a loop on it for say, 100,000 iterations, would that accomplish something similar to the strength/security of bcrypt?
Salts can only help you so far. If the hashing algorithm you use is so fast that there is little to no cost for generating rainbow tables, your security is still compromised.
A few pointers:
function strong_hash($input, $salt = null, $algo = 'sha512', $rounds = 20000) {
if($salt === null) {
$salt = crypto_random_bytes(16);
} else {
$salt = pack('H*', substr($salt, 0, 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, 0, 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, 0, $count);
}
return $bytes;
}
Instead of deploying your own (inherently with flaws) hash/salt algorithm, why not use one that was developed by security professionals?
Use bcrypt. It's been developed exactly for this in mind. It slowness and multiple rounds ensures that an attacker must deploy massive funds and hardware to be able to crack your passwords. Add to that per-password salts (bcrypt REQUIRES salts) and you can be sure that an attack is virtually unfeasible without either ludicrous amount of funds or hardware.
The Portable PHP Hashing Framework in non-portable mode allows you to generate hashes using bcrypt easily.
You can also use crypt()
function to generate bcrypt hashes of input strings. If you go down that route, make sure you generate one salt per hash.
This class can automatically generate salts and verify existing hashes against an input.
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, 0, 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, 0, $count);
}
return $bytes;
}
private function encodeBytes($input) {
return strtr(rtrim(base64_encode($input), '='), '+', '.');
}
}
You may use this code as such:
$bcrypt = new Bcrypt(15);
$hash = $bcrypt->hash('password');
$isGood = $bcrypt->verify('password', $hash);