5

我在 Kohana v 2.3.4 中使用 Auth 模块。

在验证用户方面,有一个两步过程。入口点是函数登录。它的第一个任务是检索存储在数据库中的密码并检索密码并确定盐值。盐应该由一组值确定,每个值对应于 $salt.$password 散列值中的一个点,以引入盐的另一部分。就我而言,我使用的是 md5。

问题:

  1. 我找不到此 SALT 值的配置。它似乎依赖于存储在数据库中的密码中已经存在的密码。是否有一个或者我需要配置 AUTH 来这样做,因为这个登录需要是可移植的和可重现的?如果它无法检测到盐,在 hash_password 例程中,它默认使用 uniqid(),我不认为它是可移植的。

  2. 在添加用户方面,修改Auth库添加这个功能有意义吗?即,介绍我自己的自定义 SALT,我可以说,对其进行 MD5 哈希,然后使用盐生成的 md5 在 md5sum 中的给定点播种密码?

  3. 我不是安全专家,但这是否矫枉过正?当然,它可以防止要访问 md5 密码列表的人使用 md5 查找预先确定的哈希值。

  4. 如果您使用过 Kohana PHP 框架,如果您在使用它后有任何经验教训或经验可以帮助您了解解决此问题的正确方法,请告诉我。我正在阅读许多关于它的论坛和维基,但我还没有看到真正的具体意见。我本质上是在尝试获得一种可重现的方法来验证该站点中的某人,既使用 PHP,也最终使用移动设备,如 iPhone。我还在考虑最终添加对 google 朋友连接的支持,以实现 openID 支持和集成。

以下是 Kohana 中关于感兴趣功能的 Auth 模块的片段。他们有一些调试,因为我试图更好地理解发生了什么。


public function login($username, $password, $remember = FALSE)
{
    if (empty($password))
        return FALSE;

    if (is_string($password))
    {
        // Get the salt from the stored password
        $salt = $this->find_salt($this->driver->password($username));
        Kohana::log('debug', "--- Auth_Core login salt = $salt ");
        Kohana::log('debug', "--- Auth_Core login pass = $password ");

        // Create a hashed password using the salt from the stored password
        $password = $this->hash_password($password, $salt);
    }
    Kohana::log('debug', "--- Auth_Core login pass_hash = $password ");
    return $this->driver->login($username, $password, $remember);
}
public function find_salt($password)
{
    $salt = '';

    foreach ($this->config['salt_pattern'] as $i => $offset)
    {
        // Find salt characters, take a good long look...
        //$salt .= $password[$offset + $i];
        $salt .= substr($password, $offset + $i, 0);
    }

    return $salt;
}
public function hash_password($password, $salt = FALSE)
{
    Kohana::log('debug', "--- Auth_Core Original Pass = $password ");
    if ($salt === FALSE)
    {
        // Create a salt seed, same length as the number of offsets in the pattern
        $salt = substr($this->hash(uniqid(NULL, TRUE)), 0, count($this->config['salt_pattern']));
        Kohana::log('debug', "--- Auth_Core salt created = $salt ");
    }

    // Password hash that the salt will be inserted into
    $hash = $this->hash($salt.$password);

    // Change salt to an array
    $salt = str_split($salt, 1);

    // Returned password
    $password = '';

    // Used to calculate the length of splits
    $last_offset = 0;

    foreach ($this->config['salt_pattern'] as $offset)
    {
        // Split a new part of the hash off
        $part = substr($hash, 0, $offset - $last_offset);

        // Cut the current part out of the hash
        $hash = substr($hash, $offset - $last_offset);

        // Add the part to the password, appending the salt character
        $password .= $part.array_shift($salt);

        // Set the last offset to the current offset
        $last_offset = $offset;
    }

    Kohana::log('debug', "--- Auth_Core hashpw = $password + $hash ");

    // Return the password, with the remaining hash appended
    return $password.$hash;
}
4

2 回答 2

3

关于第 1 点,该hash_password()函数用于生成存储在数据库中的密码哈希(针对盐并包括盐)(例如在注册时),以及在需要密码时重新创建该哈希已验证(例如在登录时)。该hash_password()函数将对密码散列本身中给出的任何盐(或uniqid()如果没有给出)进行编码;这是一种加密形式,其中salt_pattern是密钥;如果salt_pattern可以保密,那么这将提供额外的安全性,因为对手将无法对散列进行离线暴力破解,因为散列方法不可重现(如果可以salt_pattern保密):

// Signup time; forget about uniqid(); you can use any salt that
// you please; once the password hash is stored in the database there
// is no need to know where your salt came from since it will be
// included in the password hash.
$password_hash = hash_password($password, FALSE);

// Login time; note that the salt is taken from the password hash itself.
$reproduced = hash_password($password, find_salt($password_hash));
$verifies   = $password_hash == $reproduced;

hash_password()函数首先将密码与 salt 进行哈希处理,然后将 salt 的每个字符插入密码哈希中相应salt_pattern偏移量的位置。find_salt()将提取这些盐字符,以便可以复制哈希。您可以将其视为hash_password()对盐进行加密和find_salt()解密。虽然你也可以看到它hash_password()隐藏了盐并find_salt()找到了它,但我认为这种加密方法不能称为隐写术,因为从代码中可以清楚地看出有一个盐与密码哈希一起存储(存在盐不是秘密)。

关于第 2 点,使用您自己的 salt 非常简单,并且与 Auth 模块和现有数据库完全兼容。

关于第 3 点,使用每个用户的盐(uniqid()默认情况下)并不过分。尤其是 MD5,它出于安全目的而被破坏,并且在当今的技术中发现冲突已经很实用。更好的方法是使用bcrypt()故意较慢的散列算法来阻止暴力破解尝试。

关于第 4 点,我之前没有使用过 Kohana 框架,但是复制或移植 Auth 模块很简单。必须注意salt_pattern不要忘记或丢失,因为它是散列算法的重要组成部分。也应该保密,salt_pattern因为它是唯一可以防止确定的对手暴力破解密码哈希的方法。uniqid()只是一个合理的默认值,可以替换为您想要的任何内容(只要它是每个用户而不是站点范围内的恒定值。)


此外,关于便携式bcrypt()和 PHP的 stackoverflow 上有一个非常好的答案。当然,这与 Auth 模块兼容,但我还是想提一下,因为最好的做法是使用慢速散列,而不是依赖难以保存的秘密,比如salt_patten.

于 2009-11-16T08:08:40.330 回答
3

问题 1. salt 配置存储在config/auth.php. 在 中找到该文件modules/auth/config,然后在您的app/config文件夹中(您可能已经知道,Kohana 使用级联文件系统机制)。鼓励您自定义到app/config/文件夹中的默认文件如下所示:

<?php defined('SYSPATH') OR die('No direct access allowed.');

return array
(
  'driver' => 'ORM',
  'hash_method' => 'sha1',
  'salt_pattern' => '1, 3, 5, 9, 14, 15, 20, 21, 28, 30',
  'lifetime' => 1209600,
  'session_key' => 'auth_user',
  'users' => array
  (
      // 'admin' => 'b3154acf3a344170077d11bdb5fff31532f679a1919e716a02',
  ),
);

问题 2。在我看来,Auth 使用的密码散列机制,即带有盐插入的 SHA1,是非常安全的,只要你保持你的盐,即你的auth.php文件,安全。

问题 3. Auth 内置哈希机制使用 SHA1,它比 MD5 相对更防破解,所以我会说不要使用 MD5 方式,无论您的方案看起来多么复杂。安全专家 Thomas Ptacek 在他的博客中写道:

不完全是。使用别人的密码系统。不要建立自己的。

大多数业界最严重的安全问题(例如著名的 LANMAN 哈希)都是因为聪明的开发人员处理安全代码的方式与他们处理其余代码的方式相同。

问题 4.是的,我正在使用 Kohana 来构建我的小公司网站和我们的一些客户的网站,到目前为止,我没有发现 Auth 模块有任何问题,虽然我不能说太多,因为我真的没有将其用于真正关注安全的网站。但总的来说,我会说 Kohana 是一个出色的框架,尤其是具有级联文件系统机制的框架。

于 2009-11-16T09:58:07.800 回答