使用crypt()进行加密


Encryption using crypt()

我目前正在做一个非常安全的登录系统,但我是新的crypt()函数,需要一些快速的帮助。

我使用crypt()在注册期间加密密码字符串并将其保存到数据库中。但是,我如何能够在登录期间解密密钥?不然我该怎么做呢?或者是否可以对提交的密码字符串执行一些魔术,将其与数据库中的加密密钥进行比较?

crypt()不加密密码,它散列密码。最根本的区别是,你不能把散列密码拿回来(想想薯饼——如果你有薯饼,你就不能把土豆拿回来)。

因此,对输入应用相同的函数,并将其结果与数据库中存储的值进行比较:

$stored_pw = get_hashed_password_from_db($_POST['username']);
crypt($_POST['password'], $stored_pw) == $stored_pw

阅读crypt()的文档,了解上述代码工作背后的"魔力"。

不加密密码。相反,使用散列存储它。

流行的SO线程:我应该如何道德地接近用户密码存储以后的明文检索?

crypt()登录时提供的密码。将输出与之前的crypt()的输出进行比较。如果它们匹配,则密码匹配。

这是单向哈希函数的基本操作理论

你也应该这样做。请注意,这段代码就是我要做的,您可能想要更改一些东西。您必须定义自己唯一的salt,无论是在配置文件中还是在其他地方。它必须要么a)在全局范围内,因为我已经发布,或者你可以改变它,使其在函数中定义。而且你不是在加密,你实际上是在哈希。加密是双向的,散列是单向的加密。这意味着您无法解密散列。你只能用蛮力猜测原始的纯文本。

/*
*   Copyright (c) 2012, Macarthur Inbody
*   The following code was posted on http://stackoverflow.com/questions/8195689/encryption-using-crypt
*   The license is simply CC-by https://creativecommons.org/licenses/by/3.0/
*
*
*
*/

/*
 *
 * This is used to hash their password.
 *
 * @param   $password       string      the users supplied password
 * @param   $username       string      the users supplied username
 * @param   $rand_salt      int         the secondary salt -2^31-1 to 2^31-1 Must be defined previously.
 * @return  string the hashed password
 */
function hash_pass($username,$password,$rand_salt){
    global $unique_salt;
    $main_salt=base64_encode(hash('sha512',$username.$password.$config_salt);
    $main_salt=str_replace('+', '.', $salt);
    $main_salt=str_replace('=','/',$salt);
    $main_salt='$2$06'.$main_salt; //change this here to the cost factor that you want
    $hashed=crypt($unique_salt.$username.$password.$rand_salt,$main_salt);
    return $hashed;
}
function gen_rand_salt(){
    return rand();
}
function rand_str($length,$additional_entropy){
    $max_length=ceil($length/28);
    if(!is_defined($additional_entropy)){
        $additional_entropy='';
    }
    $str='';
    for($i=0;$i<=$max_length;++$i){
        $str.=base64_encode(sha1($i.''.microtime().$additional_entropy,true));
    }
    $str=substr($str,0,$length);
    return $str;
}
/*
*
* Generate A temp password/token
*
* This function generates a temporary password and also gives you
* the hashed password too. It is an array, arr[0]=password, arr[1]=
* hashed password. If it fails it'll return -1;
*
* @param    $username   the username
* @param    $rand_salt  the random salt value, must be given.
*
* @return   array       if it is successful array, if it fails it's a number of -1
*/ 
function generate_temp_password($username,$rand_salt){
    global $unique_salt;
    if(!is_defined($rand_salt)){
    return -1;
    }
    $pass_len=12; // change this to what you want for password recovery
    $pass_arr=Array();
    $password=rand_str($pass_len,$unique_salt.rand().$rand_salt);
    $password=substr(base64_encode(sha1($rand_str.$rand_salt,true)),0,$pass_len);
    $hashed_password=hash_pass($username,$password,$rand_salt);
    $pass_arr[0]=$password;
    $pass_arr[1]=$hashed_password;
    return $pass_arr;
}

如代码中所述,许可是CC-By,因为我认为它对大多数事情都足够好。另外,请保持块相同的链接到这个页面,因为这是我做的所有我自己的源代码。我也意识到"随机"字符串并不是真的那么随机,但它足够随机,可以被你用于它将要成为的目的。

编辑2:也要确保转义用户的用户名。我没有对密码进行转义,因为我对它进行了散列,因此转义是不必要的,因为它已经减轻了,只会浪费周期。但是只适用于的情况。确保使用mysql_real_escape_string转义用户名。如果你正在使用php5+,你应该看看mysqli(如果你正在使用mysql)。如果您使用其他系统,那么您必须自己查找,因为我只知道mysql。我要离开几天,所以我真的希望这对你有用。我会不时检查一下,但我可能会忘记……是的。我希望这对你有帮助,因为它是安全的,可靠的,应该可以很好地为你工作。

编辑3:更改了随机字符串函数,使其稍微更强,因为我忘记了这将用于生成临时密码。这应该使它足够随机,可以用于此目的,因为否则生成的密码可能会被知道确切时间(当前微时间)的人知道,尽管这是极不可能的,但这仍然使它更强大,并且应该使它免受这些类型的攻击。它不应该完全为生产做好准备,并且应该对您的系统是安全的。只要确保将$unique_salt变量设置在全局作用域中的某个位置,或者在每个函数中每次使用它时都设置它。

参见

http://php.net/manual/en/function.password-hash.php

http://php.net/manual/en/function.password-verify.php

如果你需要安全的随机值,也不要使用rand()。这是PHP中最糟糕的随机值来源。

在PHP 7中应该使用

http://php.net/manual/en/function.random-bytes.php

。有关早期版本,请参阅

http://php.net/manual/en/function.openssl-random-pseudo-bytes.php