【问题标题】:Encryption using crypt()使用 crypt() 加密
【发布时间】:2011-11-19 17:04:33
【问题描述】:

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

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

【问题讨论】:

  • 不知何故我怀疑你正在编写一个“非常安全的登录系统”......但无论如何,祝你好运。

标签: php passwords hash


【解决方案1】:

crypt() 不加密密码,它散列它们。根本区别在于,您无法取回散列密码(想想土豆煎饼 - 如果您有土豆煎饼,就无法取回土豆)。

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

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

阅读documentation on crypt(),了解上述代码背后的“魔力”。

【讨论】:

  • 感谢大家的善意和帮助,非常感谢。我不确定为什么我不能让它与 crypt() 一起工作,因为我按照你们大多数人所说的那样做了。但是现在我创建了一个自己的函数,它使用 sha1 对密码字符串进行哈希处理,然后将它与盐结合起来,然后它就真正开始工作了。另外,我很抱歉说“加密”。 :) 祝你有个愉快的夜晚!
  • @user973763 crypt 可能有点违反直觉,但如果您阅读文档,您应该能够理解它。 演示: ideone.com/mLRb3
【解决方案2】:

不要加密密码。而是将其与哈希一起存储。

热门SO线程:How should I ethically approach user password storage for later plaintext retrieval?

【讨论】:

  • crypt() 不加密密码。
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

    这也是你应该这样做的方式。请注意,这段代码是我的做法,您可能想要更改其中的一些内容。而且你必须定义自己独特的盐,无论是在配置文件中还是在其他地方。它必须 a) 在我发布的全局范围内,或者您可以更改它以使其在函数中定义。你也没有加密,你实际上是在散列。加密是两种方式,散列是一种方式的加密。这意味着您无法解密哈希。您只能暴力猜测原始纯文本。

    /*
    *   Copyright (c) 2012, Macarthur Inbody
    *   The following code was posted on http://*.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 变量,或者在每个函数中使用它时都设置它。

    【讨论】:

      【解决方案5】:

      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

      【讨论】: