如何在登录时使用salt和hash?

时间:2015-05-08 04:08:34

标签: php codeigniter hash salt

我想使用salt和hash来创建安全登录。我尝试按照this tutorial编写自己的代码,但它总是返回false。这是我的代码:

require_once 'application/third_party/Secure-Login/classes/Hashing.php';
require_once 'application/third_party/Secure-Login/classes/Salt.php';
$password = Hashing::create_hash('123456', Salt::random(12));
$old = '$2a$10$zuzycDw3Ack2cCoL3ds1sudJ2WioZ87.75ErLZVcZyh4d1hS2rHFu';

if (Hashing::validate($password, $old, Salt::random(12))) {
    echo true;
} else {
    echo false;
}

我包括两个课程:

<?php

class Hashing {

    function __construct() {}

    /**
    * @param string $pass The user submitted password
    * @param string $hashed_pass The hashed password pulled from the database
    * @param string $salt The salt pulled from the database
    * @param string $hash_method The hashing method used to generate the hashed password
    */
    static function validate($pass, $hashed_pass, $salt, $hash_method = 'sha1') {
        if (function_exists('hash') && in_array($hash_method, hash_algos())) {
            return ($hashed_pass === hash($hash_method, $salt . $pass));
        }
        return ($hashed_pass === sha1($salt . $pass));
    }

    /**
     * Generates a secure, pseudo-random password with a safe fallback.
     */
    static function pseudo_rand($length) {
        if (function_exists('openssl_random_pseudo_bytes')) {
            $is_strong = false;
            $rand = openssl_random_pseudo_bytes($length, $is_strong);
            if ($is_strong === true) {
                return $rand;
            }
        }
        $rand = '';
        $sha = '';
        for ($i = 0; $i < $length; $i++) {
            $sha = hash('sha256', $sha . mt_rand());
            $chr = mt_rand(0, 62);
            $rand .= chr(hexdec($sha[$chr] . $sha[$chr + 1]));
        }
        return $rand;
    }

    /**
     * Creates a very secure hash. Uses blowfish by default with a fallback on SHA512.
     */
    static function create_hash($string, $salt = '', $hash_method = 'sha1', $stretch_cost = 10) {
    $salt = Hashing::pseudo_rand(128);
    $salt = substr(str_replace('+', '.', base64_encode($salt)), 0, 22);
    if (function_exists('hash') && in_array($hash_method, hash_algos())) {
            return crypt($string, '$2a$' . $stretch_cost . '$' . $salt);
    }
    return Hashing::_create_hash($string, $salt);
    }

    /**
     * Fall-back SHA512 hashing algorithm with stretching.
     */
    static function _create_hash($password, $salt) {
        $hash = '';
        for ($i = 0; $i < 20000; $i++) {
            $hash = hash('sha512', $hash . $salt . $password);
        }
        return $hash;
    }

}

<?php

class Salt {

    public static function random($len = 8) {
    $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`~!@#$%^&*()-=_+';
    $l = strlen($chars) - 1;
    $str = '';
    for ($i = 0; $i < $len; ++$i) {
            $str .= $chars[rand(0, $l)];
    }
    return $str;
    }

}

请检查帮帮我!我不知道哪里出错了,它是如何运作的。非常感谢!

3 个答案:

答案 0 :(得分:1)

您的代码存在许多问题,因此我强烈建议使用函数password_hash()password_verify()进行散列。

因为你说你想了解它的工作原理,这里有一些提示:

static function create_hash($string, $salt = '', $hash_method = 'sha1', $stretch_cost = 10) {
  $salt = Hashing::pseudo_rand(128);
  $salt = substr(str_replace('+', '.', base64_encode($salt)), 0, 22);
  if (function_exists('hash') && in_array($hash_method, hash_algos())) {
    return crypt($string, '$2a$' . $stretch_cost . '$' . $salt);
  }
  return Hashing::_create_hash($string, $salt);
}

此方法首先尝试使用crypt()这是好的,因为它会生成BCrypt哈希。如果成本参数小于10,则成本参数将失败,并且可能会生成不安全的盐,并且它使用池中过多的熵。然后它检查hash()函数是否存在,但是这个函数根本不是哈希密码,而是与crypt()无关。

稍后要验证您不使用crypt(),而是使用hash()功能检查,这是与以前不同的算法。然后无法自由选择盐来验证密码,而是需要与生成哈希相同的盐,crypt()函数实际上确实在哈希值中包含了这个盐。

static function validate($pass, $hashed_pass, $salt, $hash_method = 'sha1') {
  if (function_exists('hash') && in_array($hash_method, hash_algos())) {
    return ($hashed_pass === hash($hash_method, $salt . $pass));
  }
  return ($hashed_pass === sha1($salt . $pass));
}

如果您想了解更多关于密码哈希的知识,我会邀请您阅读关于secure password storing的教程。

答案 1 :(得分:1)

如果你真的想让自己的生活更轻松。你可以去PHPASS库,它提供了你可以使用的功能。您只需要创建该类的对象并使用这些函数。

查看以下链接: 您可以从这里下载库: Download PHPASS

您可以从此处获取更多信息: Sample usage of the library

答案 2 :(得分:0)

您的示例中的一个问题是,每次要验证密码时都使用新盐,而不是使用旧盐。实际上,您需要存储用于散列密码的盐,以便对其进行验证。

请尝试以下代码:

$salt = Salt::random(12);
$password = Hashing::create_hash('123456', $salt);

验证:

if (Hashing::validate('123456', $password, $salt)) {
    echo true;
} else {
    echo false;
}

当然,每次要散列新密码时,您都需要生成一个新的盐。