Algorithm 将旧密码迁移到CakePHP 3

Algorithm 将旧密码迁移到CakePHP 3,algorithm,hash,passwords,salt,cakephp-3.0,Algorithm,Hash,Passwords,Salt,Cakephp 3.0,我正在阅读Cake 3网站上的Auth文档,对于如何将用户密码迁移到我的新应用程序,我仍然有点困惑 它说要包含FallbackPasswordHasher类,但如果是这样,我应该将旧密码的salt放在哪里(因为新站点的salt不同)?除此之外,一切似乎都不言自明 我有几个不同但相关的网站,我正在整合成一个网站,在多个企业中提供相同的服务,因此我需要从不同的网站导入用户密码,使用不同的盐。这取决于使用的旧哈希机制 根据使用的机制和算法,您可能不需要旧的salt,因为它已经附加到散列中,例如,使用B

我正在阅读Cake 3网站上的Auth文档,对于如何将用户密码迁移到我的新应用程序,我仍然有点困惑

它说要包含FallbackPasswordHasher类,但如果是这样,我应该将旧密码的salt放在哪里(因为新站点的salt不同)?除此之外,一切似乎都不言自明

我有几个不同但相关的网站,我正在整合成一个网站,在多个企业中提供相同的服务,因此我需要从不同的网站导入用户密码,使用不同的盐。

这取决于使用的旧哈希机制 根据使用的机制和算法,您可能不需要旧的salt,因为它已经附加到散列中,例如,使用
Blowfish
密码散列器散列的密码,或者通常使用
crypt()
散列的密码,它们可以通过
默认值
密码哈希器进行验证

因此,如果所有密码都是这样,那么您根本不需要使用
回退
密码哈希器,而是可以只使用
默认
密码哈希器,并在必要时重新刷新密码


无盐杂烩 对于使用不将salt附加到哈希的机制进行哈希的密码,例如
md5()
sha1()
mhash()
,等等,您可能需要一个自定义的遗留密码哈希器,该哈希器包含用于旧密码的salt

在大多数情况下,
WeakPassword
hasher应该完成这项工作,它使用旧的Cake 2机制和salt配置,即全局
Security.salt
选项和
hashType
hasher选项

请参见

如果弱哈希器不适合您,因为您在旧应用程序中使用了自定义哈希器,那么您将需要自定义遗留哈希器。一个包含salt的遗留密码哈希器的示例应该与示例一样简单

namespace-App\Auth;
使用Cake\Auth\AbstractPasswordHasher;
类LegacyPasswordHasher扩展了AbstractPasswordHasher{
公用函数哈希($password){
抛出new\LogicException('您真的不应该使用我!');
}
公共函数检查($password,$hashedPassword){
//使用传统的salt进行比较
返回sha1($password.'legacy salt here')==$hashedPassword;
}
}
注意,在使用
回退
散列程序的情况下,传统散列程序不需要实现
hash()
来实际散列某些内容,因为您不应该将其用于新的散列


每个应用程序使用不同的盐和/或算法 使用来自不同来源的密码,使用不同的盐,会使事情变得更复杂

有多种方法可以解决这个问题,最明显的一种方法(因为这就是
回退
哈希器的工作原理)是为每个应用程序创建一个单独的定制遗留哈希器,不同的哈希器将使用适当的salt,也可能是针对特定应用程序的算法

然后,您所需要做的就是依靠
回退
散列程序迭代所有遗留散列程序,直到其中一个成功验证密码

'passwordHasher'=>[
'className'=>'Fallback',
'Hasher'=>['Default','LegacyApp1','LegacyApp2','LegacyApp3',/*…*/]
]
就这些? 基本上,是的,这里唯一的问题可能是冲突,即App X的哈希程序将成功验证密码,而App Y的哈希程序通常会将密码的来源评估为
false

在这种情况下,无论出于何种原因都可能出现这种情况(即使对于非常弱的MD5,通常也不太可能出现这种情况),您必须寻求更严格的解决方案

可能有10种方法可以解决这样的问题,因此,由于冲突不太可能发生,我将坚持使用我认为最基本的方法,即在合并密码之前修改密码,以便添加标识旧应用程序的标识符,然后,遗留密码哈希器可以使用它来选择适当的salt和算法

一个例子 例如,如果应用程序1的旧密码为

de1566cc82d9fda1ac39a28a45afe3671d9ef880
prepend
app1
(使用在任何旧密码散列和新密码散列中都不能出现的唯一分隔符)使密码列包含以下内容

app1:::de1566cc82d9fda1ac39a28a45afe3671d9ef880
在您的传统密码哈希器中,检查它是否执行以下操作

app1:::de1566cc82d9fda1ac39a28a45afe3671d9ef880
公共函数检查($password,$hashedPassword){
if(strpos($hashedPassword,,:')==false){
//这不是您要查找的密码
返回false;
}
//将标识符与密码分开
列表($app,$hashedPassword)=分解(“:::”,$hashedPassword,2);
//使用特定于应用程序的遗留算法和SALT创建比较哈希
交换机($app){
案例“app1”:
$compare=sha1($password'375828236784563245364');
打破
案例'app2':
$compare=md5('legacy-salt-for-app-2'.$password);
打破
//等
违约:
返回false;
}
返回$compare===$hashedPassword;
}
正如最初提到的,有很多方法可以解决这个问题,所显示的方法只是其中之一,但是这应该会提示您通常需要什么来完成这样的任务



请注意,这里的所有示例代码都未经测试

对于任何想知道这是如何解决的人来说:以下是我所做的,基于ndm的回答

  • 在src中创建一个名为“Auth”的文件夹(同一目录控制器,型号,
     'authenticate' => [
          'Form' => [
               'passwordHasher' => [
                    'className' => 'Fallback',
                    'hashers' => ['Default', 'Legacy']
                    // 'Default' is your main one - I added 'Legacy' here
                    // 'Legacy is called if 'Default' fails - refers to our php file we just made
                ]
           ]
     ]