使用sha1和盐值存储密码

3

我有一个用 PHP 编写的简单注册脚本,我只是想知道我所采用的方法是否足够安全来存储用户密码。我正在生成一个 32 位的随机盐,并将其附加到一个 sha1 哈希密码后面。

//create new validator object
    $validator = new data_validation();
    //validate user input
    $firstName = $validator->validate_fname($firstName); //is the first name a string?
    $lastName = $validator->validate_lname($lastName); // is the last name a string?
    $username = $validator->validate_username($username); // is the username a string?
    $email = $validator->validate_email($email); //is the email in valid format?

    //make sure there isn't duplicate emails
    $valQuery = $link->query("SELECT email FROM users WHERE email = '" .$email. "'");

    if ($valQuery->num_rows == 1) {
        echo "An email is already registered with that address";
        return false;
    }

    // generate a random salt for converting passwords into sha1
    $salt = $link->real_escape_string(bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM)));
    $saltedPW =  $password . $salt;
    $hashedPW = sha1($saltedPW);

    mysqli_connect($db_host, $db_user, $db_pass) OR DIE (mysqli_error());
    // select the db
    mysqli_select_db ($link, $db_name) OR DIE ("Unable to select db".mysqli_error($db_name));

     // our sql query
    $sql = "INSERT INTO users (first_name, last_name, username, email, password, salt) VALUES ('$firstName', '$lastName', '$username', '$email', '$hashedPW', '$salt');";

    //save the updated information to the database          
    $result = mysqli_query($link, $sql) or die("Error in Query: " . mysqli_error($link));

    if (!mysqli_error($link)) 
    {
        $row = mysqli_fetch_assoc($result);
        $_SESSION['user_id'] = $row['user_id'];
        $_SESSION['loggedin'] = TRUE;
        header("Location: ../home");
    }

此外,我正在使用过程化和面向对象的php结合。大部分代码都是过程化的,但是有一些面向对象的类,比如你在上面脚本中看到的验证类。同时使用这两种风格会造成性能问题吗?


可能是PHP密码的安全哈希和盐的重复问题。 - Brendan Long
完全不是重复的问题。我甚至没有看到任何与我的脚本或问题类似的东西?我想知道的只是,如果这个脚本用于大规模存储用户密码,是否足够安全? - Ty Bailey
@TyBailey 你的问题只是那个问题的一个具体案例——如何在PHP中安全地哈希密码。那个问题上的答案也适用于你的问题(不,你的方法不安全)。 - Brendan Long
这就是你需要说的全部。没有必要指责我发布了重复的问题。我很感激你下面的回答,但仅仅因为一些问题被类似地提出并不意味着它们是重复的。你所指向的那个问题充满了有用的信息,但它并没有回答我的问题。然而,你做到了。所以谢谢你。 - Ty Bailey
2个回答

6

不行。停止你正在做的事情,阅读如何安全地哈希密码,然后阅读PHP密码的安全哈希和盐

最重要的是:

  • 如果可以,请使用scrypt;如果不能,请使用bcrypt。
  • 如果不能使用bcrypt或scrypt,请使用PBKDF2。

请参考这个答案以比较PBKDF2、bcrypt和scrypt。

还要参考常见链接文章如何安全存储密码

[MD5,SHA1,SHA256,SHA512,SHA-3等]都是通用哈希函数,旨在以尽可能短的时间计算大量数据的摘要。这意味着它们非常适合确保数据的完整性,但对于存储密码来说却毫无用处。 PHPass可能是在PHP中执行bcrypt哈希的最简单方法。您还可以使用crypt functionCRYPT_BLOWFISH困难的方式进行操作,但请注意,有很多方法可以出错,并且界面相当晦涩(例如如何指定盐值)。

谢谢你的建议!-- 你能否解释一下bcrypt和scrypt之间的区别以及为什么scrypt更安全?我阅读了你指向我的一些信息,但它们都没有提供两者的比较。 - Ty Bailey
1
@TyBailey 我之前问过一个问题,这里有一些很好的解释。简而言之,有三个主要的密钥派生函数:PKBDF2使用可变数量的处理器时间,让您调整哈希函数运行的迭代次数,但在硬件上实现很容易(这很糟糕)。bcrypt也可以控制处理器时间,但在硬件上实现相对昂贵。scrypt具有可变的CPU时间和内存需求,在硬件实现中内存非常昂贵。 - Brendan Long
1
此外,PBKDF2是IETF标准,在某些情况下可能很重要(如果您需要使用它)。我认为PBKDF2和bcrypt都已经存在了大约12年左右,而scrypt只有几年的历史。在安全方面,老的东西更好(主要是因为这是我们证明一个函数不容易被破解的唯一证据)。而且,由于它们已经存在了这么长时间,所以很容易找到PBKDF2和bcrypt的实现。 - Brendan Long

2

在过程式编程和面向对象编程之间切换本身不会影响性能。加载和实例化类的开销是可以忽略的。然而,管理一个非面向对象代码库的增长可能是一项非常重要的任务——特别是在全局命名空间中处理所有内容。

添加一个额外的字段到您的插入操作(盐)也不会影响任何事情。通过将其附加到密码末尾使用盐不会给sha1算法增加额外开销。

我有点困惑您选择如何生成随机盐,但它看起来也不需要太多系统资源。


那么盐到底有什么作用?它为每个密码生成一个随机的盐,将其附加到密码上,然后使用附加了盐的密码进行sha1哈希。你是说我不需要在数据库中存储它吗? - Ty Bailey
不,生成和存储是可以的(你需要它来解密),但我觉得你现在这样做很有趣。 - Ray

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接