Password complexity and blacklist in Symfony (optionally with FOSUserBundle)

Written by Pim on Friday December 2, 2016 - Comment - Permalink
Category: php - Tags: php, symfony2, security, fosuserbundle

There are many blog posts about "worst passwords" and lists of "common passwords" which indicate that users don't really think about safe and complex password like we developers do. To protect our users we have to require them to use a password which meets a set of requirements, like a minimal amount of characters and the usage of special characters. As a Symfony developer you can add validation on form fields rather easily, and also for user passwords.

RollerworksPasswordStrengthBundle

Constraints

The RollerworksPasswordStrengthBundle is a password strength and blacklisting constraint bundle. The bundle provides three constraints out-of-the-box:

  • Strength validation
  • Requirements validation
  • Password blacklisting

Strength validation

Validates the user password on strength (weak, medium, strong, ...) and every strength has an own set of requirements:

  • 1 - Very weak: any character is allowed (example: "1234567890" or "qwerty")
  • 2 - Weak: at least one lower and one upper
  • 3 - Medium: at least one lower, one upper and one number
  • 4 - Strong: at least one lower, one upper, one number and one special character
  • 5 - Very strong: at least one lower, one upper, one number, one special character and a minimal length of 12

When the requirements are not met, a validation error is returned giving the user tips to achieve a stronger password.

Requirements validation

Validates the user password using explicitly defined requirements like letters, at least one upper or lower, special characters, etc. You can configure the following:

  • Minimal length of the password
  • If letters are required
  • If at least one upper and one lower are required
  • If numbers are required
  • If special characters are required

When the requirements are not met, a validation error is returned for the requirement(s) you don't meet.

Password blacklisting

Sometimes there are environment where you want to forbid a password from usage (example: Admin!01). By using password blacklists you can create a list of passwords which shouldn't be accepted. You can do this be defining an array, SQLite DB or using other database supporting PDO.

Usage

The bundle is available in packagist and can be downloaded with composer:

$ php composer.phar require rollerworks/password-strength-bundle

After the download is complete, add the bundle to your AppKernel.php:

$bundles = array(
    // ...
    new Rollerworks\Bundle\PasswordStrengthBundle\RollerworksPasswordStrengthBundle(),
    // ...
);

The bundle is now active and the constraints are ready to use.

Password strength

First we add the password strength validation constraint to our password field of the User entity. I'm not a fan of annotations so I use YAML configuration instead.

AppBundle/Resources/config/validation.yml

AppBundle\Entity\User:
     properties:
         plainPassword:
             - Rollerworks\Bundle\PasswordStrengthBundle\Validator\Constraints\PasswordStrength:
                 minLength: 8
                 minStrength: 4

We defined a minimum length of 8 character and a strength level of 4 (Strong).

Result: After clearing the cache I cannot use a weak password anymore when I change my password in the application.

Password blacklist

I want to use a SQLite database as my password blacklist database. I create a new SQLite file and add some configuration to my config.yml file:

# Password blacklist
rollerworks_password_strength:
    blacklist:
        default_provider: rollerworks_password_strength.blacklist.provider.sqlite
        providers:
            sqlite:
                dsn: "sqlite:%kernel.root_dir%/Resources/password_blacklist.db"

In the validation file I add the password blacklist constraint.

AppBundle/Resources/config/validation.yml

AppBundle\Entity\User:
     properties:
         plainPassword:
             - Rollerworks\Bundle\PasswordStrengthBundle\Validator\Constraints\Blacklist: ~

FOSUserBundle

The RollerworksPasswordStrengthBundle works fine with any implementation but probably you're using FOSUserBundle as your user management system. If you do, you should also add extra validation constraints for the Hotflo\System\UserBundle\Form\Model\ChangePassword class.

Example:

AppBundle\Entity\User:
     properties:
         plainPassword:
             - Rollerworks\Bundle\PasswordStrengthBundle\Validator\Constraints\PasswordStrength:
                 minLength: 8
                 minStrength: 4
             - Rollerworks\Bundle\PasswordStrengthBundle\Validator\Constraints\Blacklist: ~

Hotflo\System\UserBundle\Form\Model\ChangePassword:
     properties:
         new:
             - Rollerworks\Bundle\PasswordStrengthBundle\Validator\Constraints\PasswordStrength:
                 minLength: 8
                 minStrength: 4
             - Rollerworks\Bundle\PasswordStrengthBundle\Validator\Constraints\Blacklist: ~

More documentation is available at the GitHub page of RollerworksPasswordStrengthBundle.