Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best flexible rails password security implementation [closed]

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:

  • Devise Security Extensions, which has a very simple regex for checking that there is uppercase, lowercase, and digits

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).

like image 811
d3vkit Avatar asked Feb 26 '14 20:02

d3vkit


1 Answers

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.

like image 128
Pierre Avatar answered Nov 01 '22 06:11

Pierre