【问题标题】:Which hashing algorithm to use for Password PHP [duplicate]密码PHP使用哪种哈希算法[重复]
【发布时间】:2012-09-06 08:39:50
【问题描述】:

可能重复:
Secure hash and salt for PHP passwords

对于php文件中密码的加密,我想改成sha256或者md5而不是使用 sha1 作为 iIwent 进行在线研究,他们说 sha1 不是如此安全。

如何更改php文件?

<?php

class DB_Functions {

private $db;

//put your code here
// constructor
function __construct() {
    require_once 'DB_Connect.php';
    // connecting to database
    $this->db = new DB_Connect();
    $this->db->connect();
}

// destructor
function __destruct() {

}

/**
 * Storing new user
 * returns user details
 */
public function storeUser($name, $nric, $email, $license, $address, $postal_code, $password) {
    $hash = $this->hashSSHA($password);
    $encrypted_password = $hash["encrypted"]; // encrypted password
    $salt = $hash["salt"]; // salt
    $result = mysql_query("INSERT INTO users(name, nric, email, license, address, postal_code, encrypted_password, salt, created_at) VALUES('$name', '$nric', '$email', '$license', '$address', '$postal_code', '$encrypted_password', '$salt', NOW())");
    // check for successful store
    if ($result) {
        // get user details 
        $uid = mysql_insert_id(); // last inserted id
        $result = mysql_query("SELECT * FROM users WHERE uid = $uid");
        // return user details
        return mysql_fetch_array($result);
    } else {
        return false;
    }
}

/**
 * Get user by nric and password
 */
public function getUserByNricAndPassword($nric, $password) {
    $result = mysql_query("SELECT * FROM users WHERE nric = '$nric'") or die(mysql_error());
    // check for result 
    $no_of_rows = mysql_num_rows($result);
    if ($no_of_rows > 0) {
        $result = mysql_fetch_array($result);
        $salt = $result['salt'];
        $encrypted_password = $result['encrypted_password'];
        $hash = $this->checkhashSSHA($salt, $password);
        // check for password equality
        if ($encrypted_password == $hash) {
            // user authentication details are correct
            return $result;
        }
    } else {
        // user not found
        return false;
    }
}

/**
 * Check user is existed or not
 */
public function isUserExisted($nric) {
    $result = mysql_query("SELECT nric from users WHERE nric = '$nric'");
    $no_of_rows = mysql_num_rows($result);
    if ($no_of_rows > 0) {
        // user existed 
        return true;
    } else {
        // user not existed
        return false;
    }
}

/**
 * Encrypting password
 * @param password
 * returns salt and encrypted password
 */
public function hashSSHA($password) {

    $salt = sha1(rand()); //algorithm hash
    $salt = substr($salt, 0, 10);
    $encrypted = base64_encode(sha1($password . $salt, true) . $salt);
    $hash = array("salt" => $salt, "encrypted" => $encrypted);
    return $hash;
}

/**
 * Decrypting password
 * @param salt, password
 * returns hash string
 */
public function checkhashSSHA($salt, $password) {

    $hash = base64_encode(sha1($password . $salt, true) . $salt);

    return $hash;
}

}

?> 

【问题讨论】:

  • 您好。 1.这不是你的文件吗?文件中有很多部分(可能还有数据库),您必须更改这些部分才能使用不同的散列算法,您应该真正查看文件并弄清楚它做了什么以确保它正常工作。 2. 如果您担心安全性,那么您真的应该使用 BCRYPT 来散列密码。 BCRYPT 计算哈希的速度很慢,因此可能需要更长时间的暴力攻击。
  • 另见 Openwall 的PHP password hashing framework (PHPass)。它的便携性和强化了针对用户密码的一些常见攻击。编写框架 (SolarDesigner) 的人与编写 John The Ripper 并在 Password Hashing Competition 担任评委的人是同一个人。所以他对密码攻击略知一二。

标签: php encryption passwords


【解决方案1】:

哈希密码最安全的方法是使用BCrpyt
MD5、SHA1、SHA256 被认为是不安全的。

有关此问题的更多信息,请参阅有关安全性的帖子: https://security.stackexchange.com/questions/211/how-to-securely-hash-passwords

要实现 BCrpyt 密码哈希,请参阅:How do you use bcrypt for hashing passwords in PHP?

【讨论】:

  • 我明白了。我是 php 和 java 的新手。有关如何在 php 中对其进行哈希处理的任何示例?
  • 编辑为使用 BCrypt 并包含一个实现链接。
  • 当你以错误的方式做事时,BCrypt 不会拯救你。一个设置良好的 SHA-256(例如加盐)在接下来的几年里将几乎无法破解,而使用不当的 BCrypt 将容易受到彩虹表攻击。密码几乎不会通过解密散列被破解,除了未散列的常用密码。通常,问题在于周围的代码有缺陷,例如没有使用盐。与其在选择哈希算法上浪费太多时间,不如格外注意你正在有效地使用它们。
  • @Anony-Mousse - 恰恰相反,SHA-256 很容易受到彩虹表攻击(或者如果使用盐则暴力破解),因为它可以用专用硬件计算很多 too fast . Bcrypt 的优势在于,您可以选择一个成本因素来确定计算所需的时间,因此彩虹表将变得不切实际。你说得对,SHA-256 是一种安全的算法,但它不适合散列密码,因为它的暴力破解速度太快了。
  • 好吧,你就等着人们找到多少种方法来搞砸 BCrypt。 PHP 用户很有创意。
【解决方案2】:

BCrypt 是在 PHP 中加密密码的最佳选择。下面是一些可以帮助您的代码:

<?php
/*
By Marco Arment <me@marco.org>.
This code is released in the public domain.

THERE IS ABSOLUTELY NO WARRANTY.

Usage example:

// In a registration or password-change form:
$hash_for_user = Bcrypt::hash($_POST['password']);

// In a login form:
$is_correct = Bcrypt::check($_POST['password'], $stored_hash_for_user);

// In a login form when migrating entries gradually from a legacy SHA-1 hash:
$is_correct = Bcrypt::check(
$_POST['password'],
$stored_hash_for_user,
function($password, $hash) { return $hash == sha1($password); }
);
if ($is_correct && Bcrypt::is_legacy_hash($stored_hash_for_user)) {
$user->store_new_hash(Bcrypt::hash($_POST['password']));
}

*/

class Bcrypt
{
    const DEFAULT_WORK_FACTOR = 8;

    public static function hash($password, $work_factor = 0)
    {
        if (version_compare(PHP_VERSION, '5.3') < 0) throw new Exception('Bcrypt requires PHP 5.3 or above');

        if (! function_exists('openssl_random_pseudo_bytes')) {
            throw new Exception('Bcrypt requires openssl PHP extension');
        }

        if ($work_factor < 4 || $work_factor > 31) $work_factor = self::DEFAULT_WORK_FACTOR;
        $salt =
            '$2a$' . str_pad($work_factor, 2, '0', STR_PAD_LEFT) . '$' .
            substr(
                strtr(base64_encode(openssl_random_pseudo_bytes(16)), '+', '.'),
                0, 22
            )
        ;
        return crypt($password, $salt);
    }

    public static function check($password, $stored_hash, $legacy_handler = NULL)
    {
        if (version_compare(PHP_VERSION, '5.3') < 0) throw new Exception('Bcrypt requires PHP 5.3 or above');

        if (self::is_legacy_hash($stored_hash)) {
            if ($legacy_handler) return call_user_func($legacy_handler, $password, $stored_hash);
            else throw new Exception('Unsupported hash format');
        }

        return crypt($password, $stored_hash) == $stored_hash;
    }

    public static function is_legacy_hash($hash) { return substr($hash, 0, 4) != '$2a$'; }
}


// =============================================================================
// Or, if you don't want the class structure and just want standalone functions:
// =============================================================================

function bcrypt_hash($password, $work_factor = 8)
{
    if (version_compare(PHP_VERSION, '5.3') < 0) throw new Exception('Bcrypt requires PHP 5.3 or above');

    if (! function_exists('openssl_random_pseudo_bytes')) {
        throw new Exception('Bcrypt requires openssl PHP extension');
    }

    if ($work_factor < 4 || $work_factor > 31) $work_factor = 8;
    $salt =
        '$2a$' . str_pad($work_factor, 2, '0', STR_PAD_LEFT) . '$' .
        substr(
            strtr(base64_encode(openssl_random_pseudo_bytes(16)), '+', '.'),
            0, 22
        )
    ;
    return crypt($password, $salt);
}

function bcrypt_check($password, $stored_hash, $legacy_handler = NULL)
{
    if (version_compare(PHP_VERSION, '5.3') < 0) throw new Exception('Bcrypt requires PHP 5.3 or above');

    if (bcrypt_is_legacy_hash($stored_hash)) {
        if ($legacy_handler) return call_user_func($legacy_handler, $password, $stored_hash);
        else throw new Exception('Unsupported hash format');
    }

    return crypt($password, $stored_hash) == $stored_hash;
}

function bcrypt_is_legacy_hash($hash) { return substr($hash, 0, 4) != '$2a$'; }

【讨论】:

  • 所以我只需要将我的 php 函数 public function hashSSHA($password) and public function checkhashSSHA($salt, $password) 更改为 function bcrypt_hash , function bcrypt_check and function bcrypt_is_legacy_hash ?如何实施?
  • 您可以执行bcrypt_hash('yourpassword') 之类的操作,这将返回一个 BCrypt'd Salt'd 密码。 cmets中类的顶部也有使用示例。
  • 最简单的可能方法是搜索并替换“sha1”为“bcrypt_hash”,只要数据库列不仅仅是一个 VARCHAR(30),它的工作方式应该完全相同。您需要为此代码启用 openssl。
【解决方案3】:

不要不要花太多时间玩弄不同的哈希算法和你自己的完美存储方式很有可能在这里犯了一些错误,而最好的散列算法不能拯救你。

我强烈建议人们坚持使用标准库。它们具有很好的功能,无论如何都被主机系统使用。这尤其意味着 crypt 函数,它可能被操作系统的各个部分大量使用。

现在,当我提到crypt 时,有些人会心脏病发作。这很好,因为这意味着他们只是在重复原始 UNIX 时代的信息,并且没有太多了解。 现代 cryptDES 能做的更多。只是不要将它与DES 一起使用。

这是我的 Linux 系统上crypt 手册页的一部分(但 BSD 也支持此功能)。所有这些都应该在 PHP 中直接可用:

          ID  | Method
          ---------------------------------------------------------
          1   | MD5
          2a  | Blowfish (not in mainline glibc; added in some
              | Linux distributions)
          5   | SHA-256 (since glibc 2.7)
          6   | SHA-512 (since glibc 2.7)

   So   $5$salt$encrypted   is   an   SHA-256   encoded    password    and
   $6$salt$encrypted is an SHA-512 encoded one.

   "salt" stands for the up to 16 characters following "$id$" in the salt.
   The encrypted part of the password string is the actual computed  pass-
   word.  The size of this string is fixed:

   MD5     | 22 characters
   SHA-256 | 43 characters
   SHA-512 | 86 characters

您从使用此方案中获得的巨大好处是您实际上可以在您的系统中使用不同的方案。

假设您有一些用户在您仍在使用MD5 的时候设置了密码。但是,任何 密码都应使用SHA-256 加密。也许几年后,您希望慢慢迁移到另一个标准,也许是Bcrypt。没问题。它只需要一个新的ID。您拥有的标准软件所有可能都支持这些哈希值。需要它们作为 unix 登录名吗?没问题。 Apache HTTP 身份验证?没问题。因为它使用的是操作系统标准。

在验证时,它将根据上次设置密码时使用的方案进行测试。所以它向后兼容向前兼容

如果你想迁移到一个新的方案,说SHA-3,当它结束时,你可以将默认哈希更改为最新的,然后询问用户设置新密码,并在某些时候禁用所有具有旧哈希 ID 的密码。将 ID 与散列一起存储是有意义的。

使用 SHA-256 方案所需要做的就是生成一个具有$5$&lt;16-chars-of-salt&gt;$ 方案的哈希。如果您想要 SHA-512,请使用 $6$&lt;16-chars-of-salt&gt;$

很简单的代码:

crypt("Hello",'$6$CygnieHyitJoconf$')

会产生

$6$CygnieHyitJoconf$vkGJm.nLrFhyWHhNTvOh9fH/k7y6k.8ed.N7TqwT93hPMPfAOUsrRiO3MmQB5xTm1XDCVlW2zwyzU48epp8pY/

正确加盐的 SHA-512 密码哈希。 不要重新发明轮子。

【讨论】:

    【解决方案4】:

    你可以使用

    $encrypted = base64_encode(hash('sha256',$password . $salt));
    

    而不是

    $encrypted = base64_encode(sha1($password . $salt, true));
    

    在函数中

    hashSSHA   
    

    【讨论】:

    • 用于编码是的。要解码您必须在 checkhashSSHA 中进行的相关更改
    • 解码相关变化?什么意思?
    • checkhashSSHA中代替这个$hash = base64_encode(sha1($password . $salt, true));需要使用$hash = base64_encode(hash('sha256',$password . $salt));
    • -1 这甚至不是远程安全的。
    【解决方案5】:

    您可以将散列函数更改为 sha256、md5 或任何其他值,但如果您的数据库已经填充了 sha1 散列密码,则它不会正常工作。在这种情况下,如果不丢弃旧数据,就无法更改哈希函数。

    【讨论】:

    • 我可以删除所有已经使用 sha1 密码的数据,然后使用新的哈希函数重新创建新数据。对吗?
    • 当然,如果你能做到的话。
    • YES 有办法。看看crypt 是如何解决它的,并允许不同的哈希共存。不,您通常无法重新生成数据,因为您不想存储源数据(这将是明文密码)...关键思想是在 algorithm 中包含加密散列。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-12
    • 2012-05-06
    • 2021-03-30
    • 1970-01-01
    • 2015-09-09
    • 2011-10-10
    相关资源
    最近更新 更多