Best flexible rails password security implementati

2020-07-17 05:33发布

I need to implement password security with various flexible requirements. The requirements are essentially taken from the Sans password policy:

Strong passwords have the following characteristics:

Contain at least three of the five following character classes:

  • Lower case characters
  • Upper case characters
  • Numbers
  • Punctuation
  • “Special” characters (e.g. @#$%^&*()_+|~-=`{}[]:";'<>/ etc)
  • Contain at least fifteen alphanumeric characters.

There are also requirements of not allowing the users email address to appear in the password.

Ideally, I would like a gem that would handle this - it would be more widely tested and used, and we would be less likely to have bugs.

If no gem covers this, then what is the best and most-hardened method to handle these requirements? Ideally we would be able to say that we are not only safe, but safe because we have an industry standard implementation.

The gems I have found so far are:

and

  • Strong Password, which looks to just provide an entropy check to let the user know if their password is strong.

(We are using Rails 3.2.17 and Ruby 1.9.3, but are planning on moving to Rails 4 and Ruby 2 soon, so newer solutions are also welcome).

2条回答
够拽才男人
2楼-- · 2020-07-17 05:44

we've been using devise security extension for a while now. It has a lot of interesting features (e.g. password history, password expiration...).

For password complexity we wanted something that was a bit more configurable (in your example: letting customer choose how many levels of comlexity they wanted).

So we rolled out our own solution based on a score: 3 out of 5 (in you example) means that we're testing each characterisitc and give one point if it's found. If the total score is equal or greater than required score, then the password is fine.

In terms of code, our validation looks like this:

validate :password_complexity

def password_complexity
 return if password.nil?

 if password.size < 8
   errors.add :password, "Must be at least 8 characters long."
   return
 end

 required_complexity = 3 # we're actually storing this in the configuration of each customer

 if !CheckPasswordComplexityService.new(password, required_complexity).valid?
   errors.add :password, "Your password does not match the security requirements."
 end
end

and the service that checks for the complexity looks like this:

class CheckPasswordComplexityService

  attr_reader :password, :required_complexity

  def initialize(password, required_complexity)
    @password = password
    @required_complexity = required_complexity
  end

  def valid?
    score = has_uppercase_letters? + has_digits? + has_extra_chars? + has_downcase_letters?

    score >= required_complexity
  end

  private

  def has_uppercase_letters?
    password.match(/[A-Z]/) ? 1 : 0
  end

  def has_digits?
    password.match(/\d/) ? 1 : 0
  end

  def has_extra_chars?
    password.match(/\W/) ? 1 : 0
  end

  def has_downcase_letters?
    password.match(/[a-z]{1}/) ? 1 : 0
  end
end

Then it becomes very easy to add some new characteristics you want to check.

查看更多
等我变得足够好
3楼-- · 2020-07-17 05:50

I don't think a gem is the correct thing to use here. Just use a validation:

validate :secure_password

def secure_password
    return false if (password =~ /[a-z]/).blank? #lower letter test
    return false if (password =~ /[A-Z]/).blank? #upper letter test
    return false if (password =~ /[0-9]/).blank? #number test
    ...
end
查看更多
登录 后发表回答