【问题标题】:Convert PHP's password_verify to Ruby on Rails将 PHP 的 password_verify 转换为 Ruby on Rails
【发布时间】:2016-12-23 08:15:26
【问题描述】:

我们正在将我们的网站从旧的 PHP 框架转换为 Rails,并且非常希望用户能够继续使用旧密码登录。在旧站点上,我们使用 password_hash 和 password_verify 来散列和验证密码。但是,在 Rails 上,我似乎无法验证旧密码。

这是我们在 PHP 中所拥有的:

哈希:

password_hash($user['salt'] . $password . $user['salt'], PASSWORD_DEFAULT);

验证:

password_verify($user['salt'] . $password . $user['salt'], $user['password'])

在新的 Rails 框架上,我们使用 Devise 并构建了一个自定义迁移脚本来移动所有内容并根据存储在数据库中的 password_version 识别正确的密码哈希方法,这就是我在我的内部使用的用户模型:

def valid_password?(password)
  if password_version == 'legacy'
    hash = BCrypt::Password.new(encrypted_password)
    hash_str = password_salt+password+password_salt

    return hash.is_password? hash_str
  end

  super(password)
end

任何想法将不胜感激

【问题讨论】:

  • password_verify 不是很复杂。传入新的密码和原始密码哈希。将 crypt 方法 + salt 从散列中提取出来,使用它们重新散列新的密码,然后比较生成的散列值。
  • @Script47 是的,它应该在那里。
  • @MarcB 是的,这基本上就是我想要做的。根据我的理解,它应该使用 bcrypt,所以 rails 部分应该可以工作,我会想到
  • password_hash 应该可以在不需要盐的情况下工作。添加一个只会把事情搞砸。你为什么这样做?
  • Please don't add your own salt to password_hash。让它自己添加。您将获得存储在哈希中的盐

标签: php ruby-on-rails ruby


【解决方案1】:

PHP password_hash 密码的格式大致如下:

$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a

默认的 Ruby Bcrypt 方法生成以下形式的密码:

$2a$10$GtKs1Kbsig8ULHZzO1h2TetZfhO4Fmlxphp8bVKnUlZCBYYClPohG

对于一个干净的解决方案,您始终可以通过 $2y$2a 前缀来区分两者。当格式列已经融入格式时,就不需要格式列了。

例如:

case (encrypted_password[0,3])
when '$2y'
  # Legacy PHP password
  BCrypt::Password.new(encrypted_password.sub(/\A\$2y/, '$2a')).is_password?(salt + password + salt)
when '$2a'
  # Ruby BCrypt password
  BCrypt::Password.new(encrypted_password).is_password?(password) 
else
  # Unexpected type?
end

成功验证密码后,您需要做的是使用 Ruby 的方法将密码重新写入数据库,以逐步替换所有旧的 PHP 格式。

【讨论】:

  • 是的,正如我在问题中所说,我已经知道哪个密码是哪个,这只是(在 ruby​​ 中)使用 PHP 哈希验证密码的问题。我想保留 password_version 因为有一个更旧的旧密码版本正在使用,因为当前站点没有用新格式替换这些,它只是允许它们继续工作。我已经让那个工作正常了,因为它只是一个加盐的哈希
  • 我是说应该用新版本替换它们。你这里有一些测试数据可以用来说明想要的输出吗?
  • 它将替换它们,旧版本没有,所以我使用 BCrypt 将两种旧密码哈希方法转换为新方法
  • @jakeb 我已经用一些示例代码更新了答案。您的 valid_password? 方法需要同时使用提供的密码和旧的 salt 值。
  • @jakeb 我以前在 Python 和 Node.js 中处理 PHP 密码时不得不做类似的事情。很高兴它成功了!
猜你喜欢
  • 2021-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-13
  • 2012-06-18
  • 1970-01-01
  • 1970-01-01
  • 2016-10-02
相关资源
最近更新 更多