【问题标题】:Simple but safe password hashing简单但安全的密码散列
【发布时间】:2014-06-25 22:24:45
【问题描述】:

我正在寻找一种简单(或尽可能简单)但安全的方法,用于在将用户密码提交到数据库然后从数据库中检索时对其进行散列和加盐处理。经过过去 3 小时的研究,实际上有数百种不同的方法,每个人都会说是最好的方法。

我正在寻找一种相对简单的方法来保证用户帐户的安全。显然,安全一词可以有不同的解释,但我只是希望它至少对于潜在的黑客(或任何你称之为悲伤的人)来说很难获得对用户帐户的访问权限。

我很感激我至少应该尝试一些事情,但对于我的目的来说,它们似乎都如此复杂且过于安全。

我尝试使用password_hash(),但似乎我运行的 PHP 版本早于 5.5。我知道下面的代码存在问题,但这只是我正在从事的个人项目的起点,以便更好地学习 PHP。

当前的注册表

$username = $_POST['username'];
$password = $_POST['password'];

try {   

    $result = $db->prepare("INSERT INTO 
                            user_info 
                            SET 
                            username = :user,
                            pass = :pass
                            ");
    $result->bindParam(':user', $username);
    $result->bindParam(':pass', $password);
    $result->execute();
}

catch (Exception $e) {
    echo "Could not create username";
}

if (isset($_POST['submit'])) { 
    foreach ($_POST as $field) {
        if (empty($field)) {
            $fail = true;
        }
        else {
            $continue = false;
        }
    }
    if ($field == $fail) {
        echo "You must enter a username and/or password";
    }
    else {
        echo "Your account has been successfully created.";
    }
     }

登录逻辑

$username = $_POST['username'];          
$password = $_POST['password'];

try {   

    $result = $db->prepare("SELECT username, pass FROM user_info WHERE username = :user AND BINARY pass = :pass");
    $result->bindParam(':user', $username);
    $result->bindParam(':pass', $password);
    $result->execute();
    $rows = $result->fetch(PDO::FETCH_NUM);
}

catch (Exception $e) {
    echo "Could not retrieve data from database";
    exit();
}

if ($password = $rows) {
    session_start();
    $_SESSION['username'] = $_POST['username'];
    $_SESSION['loggedin'] = true;
    include("inc/redirect.php");

} else {
    if (isset($_POST['login'])) {
        echo "Username or password incorrect (passwords are case sensitive)";
    }
}

【问题讨论】:

标签: php passwords password-storage


【解决方案1】:

使用sha1函数http://www.php.net/manual/en/function.sha1.php

这真的很简单。在输入参数中传递密码,然后将其保存在数据库中。

当您想检查密码是否正确时,只需将 sha1(密码)与存储的值进行比较。

例子:

$passwordEncrypted = sha1($password)

将 $passwordEncrypted 保存在您的数据库中

当用户想登录时:

检查这个条件:

如果 (sha1($password) ==$passwordEncrypted )

这是完整的代码:

$username = $_POST['username'];

$password = $_POST['password'];
$passwordEncrypted = sha1($password) 

    try {   

        $result = $db->prepare("INSERT INTO 
                                user_info 
                                SET 
                                username = :user,
                                pass = :pass
                                ");
        $result->bindParam(':user', $username);
        $result->bindParam(':pass', $passwordEncrypted);
        $result->execute();
    }

    catch (Exception $e) {
        echo "Could not create username";
    }

    if (isset($_POST['submit'])) { 
        foreach ($_POST as $field) {
            if (empty($field)) {
                $fail = true;
            }
            else {
                $continue = false;
            }
        }
        if ($field == $fail) {
            echo "You must enter a username and/or password";
        }
        else {
            echo "Your account has been successfully created.";
        }
         }

【讨论】:

  • 感谢您的解释和更新代码。与其他方法相比,使用这种方法有什么明显的负面影响吗?我想我应该研究一下 sha1,但这是漫长的一天!
  • 上面有人提供了一个 SO 帖子的链接,他们明确指出; Never hash passwords with SHA1 or MD5 or even SHA256! Modern crackers can exceed 60 and 180 billion hashes/second (respectively). - 他们这样做的理由是什么?
  • 不要使用 sha1。 en.wikipedia.org/wiki/SHA-1 2005 年,密码分析人员发现对 SHA-1 的攻击表明该算法可能不够安全,无法继续使用
  • 算法很多。我认为更强的是 sha512 hash('sha512', 'yourpassword');
  • @CodePoetry 我很满意,假设 sha1 方法是安全的。有些人似乎对这种特定方法不确定,这就是为什么我想澄清一下,您是否了解这种特定方法的安全性细节。
【解决方案2】:

有了password_hash(),你就走在了正确的轨道上。对于 PHP 版本 5.3.7 - 5.5,您可以使用 compatibility pack,稍后当您切换到较新的 PHP 版本时,您只需从项目中删除此 php 文件,代码仍将运行。

// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);

// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);

即使 PHP 版本低于 5.3.7,您也可以使用兼容包‌​。您只需编辑第 55 行并将算法从 sprintf("$2y$%02d$", $cost); 更改为 sprintf("$2a$%02d$", $cost);。这当然不是最佳的,但对于 5.3 和 5.3.7 之间的 PHP,这是您可以做的最好的。

其他算法(如 SHA* 或 MD5)的问题在于,它们的速度太快了。可以用普通硬件计算3 Giga SHA-1 per second,这使得暴力破解太容易了。要测试整个英语词典,您只需要几分之一毫秒。这就是为什么人们应该使用像 BCrypt 或 PBKDF2 这样具有成本因子的哈希算法,它们允许控制计算单个哈希的必要时间。

【讨论】:

    【解决方案3】:

    【讨论】:

    • 谢谢。我很好奇,这种方法到底有多安全?
    • @mayy00 - 快速散列算法不适用于散列密码。相反,应该选择一种具有成本因子的算法,该成本因子控制计算单个哈希值所需的时间。
    【解决方案4】:

    使用盐和sha256加密算法

    <?php
    // create user
    $password = $_POST['password'];
    $salt = mcrypt_create_iv(22, MCRYPT_DEV_URANDOM);
    $pass = hash("sha256", $salt.$password.$salt);
    // save salt and password hash into database
    
    // to validate user
    // 1 - get salt and password hash from database
    // 2 - prepend and append salt to the posted password
    // 3 - encrypt with the same algorithm
    // 4 - compare with stored password hash. 
    

    【讨论】:

      猜你喜欢
      • 2010-11-16
      • 2010-12-22
      • 2021-08-14
      • 2011-02-05
      • 2015-05-06
      • 2013-09-03
      • 1970-01-01
      • 2014-11-25
      • 1970-01-01
      相关资源
      最近更新 更多