Ruby on rails 使用design防止密码重用

Ruby on rails 使用design防止密码重用,ruby-on-rails,devise,Ruby On Rails,Devise,我知道在用户创建密码的一段时间后强制密码过期不是Desive逻辑的一部分,我计划编写自己的代码来实现这一点 另外,强制用户不要重复使用最后一个X(在我的例子中是10)密码中的一个密码也需要手动编码 我的想法是,我将创建一个类似于user\u passwords表的东西,并在代码中使用逻辑来确保新密码与该用户的表中的任何密码都不匹配。同时,我会将新密码插入表中,除非该用户已有10条记录,这意味着我将用新值覆盖最旧的记录。表结构如下所示: 用户密码 用户id 加密密码 创建于 如果有人有更好、更

我知道在用户创建密码的一段时间后强制密码过期不是Desive逻辑的一部分,我计划编写自己的代码来实现这一点

另外,强制用户不要重复使用最后一个X(在我的例子中是10)密码中的一个密码也需要手动编码

我的想法是,我将创建一个类似于user\u passwords表的东西,并在代码中使用逻辑来确保新密码与该用户的表中的任何密码都不匹配。同时,我会将新密码插入表中,除非该用户已有10条记录,这意味着我将用新值覆盖最旧的记录。表结构如下所示:

用户密码

  • 用户id
  • 加密密码
  • 创建于
如果有人有更好、更优雅的解决方案来处理这个问题,我将不胜感激

这个似乎能满足我的需要

但是,目前它不支持Desive 2.0或更高版本。我遇到了许多问题,不得不将我的设计降级到1.5.3。根据他们留言板上的评论,他们目前正在将gem移植到与designe2.0兼容的版本

我对它的密码可过期模块和密码可架构模块进行了旋转。一切似乎都按预期进行

它还支持secure_validatable、session_limitable和expirable,前两个我可能会在不久的将来使用

我知道在用户创建密码的一段时间后强制密码过期不是Desive逻辑的一部分,我计划编写自己的代码来实现这一点

在实践中,与安全相关的研究发现这是一个坏主意。那是因为每次改变你都会得到递减的回报。也就是说,当用户试图遵守策略时,密码开始变强,然后随着时间的推移变弱。参见彼得·古特曼和第7章,密码

从书中可以看出,其他愚蠢的事情包括复杂性要求。(反对之前,请阅读本书的相关章节)


。。。创建类似于user_passwords表的内容,并在我的代码中使用逻辑来确保新密码与该用户在该表中的任何密码都不匹配

一旦你读了这一章,我就会问:为什么你首先允许用户选择一个脆弱/受伤/损坏的密码?这些60 KB的Bloom过滤器在与以下各项结合使用时看起来非常有用:)


防止密码重复使用

将要受到伤害的重用是跨站点的密码重用。Brown、Bracken、Zoccoli和Douglas表示,这一数字在《应用认知心理学》第18卷第6期第641-651页中约占70%。Das、Bonneau、Caesar、Borisov和Wang报告的数字在2010年约为45%。请注意,混乱的网络研究必须破解密码,因此这个数字可能更高,因为他们无法恢复所有密码

根据Das、Bonneau、Caesar、Borisov和Wang-in的说法,为了使重用成为一个更严重的问题,用户必须记住大约25个不同站点的密码

几年前我甚至被这个烫伤了。我在两个低值帐户上使用了相同的密码。然后遭到黑客攻击,攻击者能够使用恢复的密码来破坏一个很少使用的电子邮件帐户


现在,当我需要凭证时,我只生成一个长的随机字符串。我甚至不用为大多数网站写下它们。当我需要再次访问某个站点时,我只需执行恢复过程。

在rails 5中,Desive_security_扩展不适用于我,我创建了我的自定义:

  • 创建迁移并添加额外的列,如: 添加列:用户,:旧密码,:文本
  • 在您的模型中添加两个回调:保存后:缓存旧过程和保存前:验证旧过程

  • 创建回调的方法:

    private
    def verify_old_pass
      if self.encrypted_password_changed?
        old_passwords.to_s.split(',').each do |pass_encrypted|
          if Devise::Encryptor.compare(self.class, pass_encrypted, password)
            errors.add(:base, 'Your password cannot be previous up to 3 back')
            return throw(:abort)
          end
        end
      end
    end
    
    def cache_old_pass # cache last 3 passwords
     if self.encrypted_password_changed?
       update_column(:old_passwords, ([self.encrypted_password] + old_passwords.to_s.split(',')[0, 3]).join(','))
     end
    end
    

在PasswordsController中,您可以检查它

class PasswordsController < Devise::PasswordsController

  def update
    current_user = User.with_reset_password_token(params[:user][:reset_password_token])
    if current_user && previous_and_new_password_is_same?(current_user)
      current_user.errors[:password] << "has been used previously."
      self.resource = current_user
      respond_with resource
    else
      super
    end
  end

  private

  def previous_and_new_password_is_same?(current_user)
    bcrypt       = ::BCrypt::Password.new(current_user.encrypted_password)
    hashed_value = ::BCrypt::Engine.hash_secret([params[:user][:password], Devise.pepper].join, bcrypt.salt)
    hashed_value == current_user.encrypted_password
  end

end
类密码控制器当前用户错误[:密码]我认为“不要使用最近10个密码中的任何一个”有点武断,除非你有具体的商业原因。您可以轻松强制执行“不要使新密码与旧密码相同”。事实上,密码很难记住,而你要做的是让用户在便笺上写下密码。这是客户的实际要求。这是一家金融公司。那么,我认为没有比你提出的更优雅的解决方案了……我发现:太棒了。用这个回答你自己的问题!我想覆盖session_limitable行为,因为我只需要http请求的行为。任何想法…告诉我们你没有保存加密或不加密的实际密码,那将是完全不负责任的。当攻击者获得DB时,他也将获得加密密钥。这不是保存未加密的密码,而是保存由Desive生成的历史密码并由Desive验证(没有黑客攻击),因此我猜Desive::Encryptor的名称有误,因为它似乎执行哈希而不是加密-这是个好消息。这将是很好的,如果解释到底发生了什么,但我猜你付出了什么。不好的命名应该受到惩罚,但我们只是编码猴子,而不是专业人士。不幸的是,密码恢复过程是穷人的双重身份验证。