Kohana:理解和复制Salt&使用Auth模块进行散列密码

时间:2009-11-16 05:39:02

标签: php security authentication login kohana

我在Kohana v 2.3.4中使用了Auth Module。

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

问题:

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

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

  3. 我不是安全专家,但这有点过分吗?当然,它可以阻止访问md5密码列表的人使用预定哈希值的md5查找。

  4. 如果您使用过Kohana PHP框架,如果您在使用它之后获得了任何经验教训或经验,可能会对此问题的正确方法有所了解,请告诉我们。我正在阅读很多关于它的论坛和维基,而且我还没有看到真正的具体意见。我本质上是试图获得一种可重现的方法来验证这个站点中的某个人,无论是使用PHP还是最终来自移动设备,如iPhone。我也在考虑最终为google friend connect添加对openID支持和集成的支持。

  5. 以下是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;
    }
    

2 个答案:

答案 0 :(得分: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的每个char插入到相应salt_pattern偏移量的密码哈希中。 find_salt()将提取这些盐字符,以便可以再现哈希值。您可以将其视为hash_password()加密盐并find_salt()对其进行解密。虽然您也可以看到它隐藏了hash_password()并且find_salt()找到了它,但我认为这种加密方法不能称为steganography,因为从代码中可以清楚地看到有一个存储有密码哈希的盐(盐的存在不是秘密)。

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

关于第3点,使用每用户盐(默认为uniqid()过度杀伤。特别是对于MD5而言,出于安全目的而破坏,并且发现碰撞已经成为当今技术的实用之处。更好的方法是使用bcrypt(),它使用有目的地较慢的散列算法来阻止暴力破坏尝试。

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


此外,关于portable bcrypt() and PHP的stackoverflow,这里有一个非常好的答案。当然与Auth模块兼容,但无论如何我想提及它,因为最好的做法是使用慢哈希而不是依赖难以保留的秘密,比如salt_patten

答案 1 :(得分: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在his blog写道:

  

不,真的。使用别人的   密码系统。不要建立自己的。

     

该行业大多数安全性最差   问题(如着名的坏LANMAN   hash)因为聪明而发生   开发人员接近安全代码   他们和其他人一样   他们的代码。

问题4。是的,我正在使用Kohana建立我的小公司网站和我们客户的一些网站,到目前为止,我发现Auth模块没有任何问题,尽管我可以我说的很多,因为我还没有真正将它用于真正的安全相关网站。但总的来说,我认为Kohana是一个优秀的框架,尤其是级联文件系统机制。