ex_nist v1.0.0 ExNist View Source

Set of Ecto.Changeset functions to validate against NIST guidelines.

Modeled after laravel-nist-password-rules

RecommendationImplementation
[...] at least 8 characters in lengthProvided by standard Ecto.Changeset validation function
Passwords obtained from previous breach corpusesThe ExNist.validate_password_breach/3 function securely checks the password against previous 3rd party data breaches, using the Have I Been Pwned - Pwned Passwords API.
Dictionary wordsThe ExNist.validate_dictionary_words/3 rule checks the password against a list of over 102k dictionary words.
Context-specific words, such as the name of the service, the usernameThe ExNist.validate_context_specific_words/3 rule checks the password does not contain the provided list of words.
Context-specific words, [...] and derivatives thereofThe ExNist.validate_derivative_words/3 rule checks the password is not too similar to the provided list of words.
Repetitive or sequential characters (e.g. ‘aaaaaa’, ‘1234abcd’)The ExNist.validate_repetitive_chars/3 and ExNist.validate_sequential_chars/3 rules checks if the password contains any repetitive or sequential characters.

Installation

The package can be installed by adding ex_nist to your list of dependencies in mix.exs:

def deps do
  [
    {:ex_nist, "~> 1.0.0"},
    # Optionally add `ex_pwned`
    # {:ex_pwned, "~> 0.1.4"}
  ]
end

The library can use the ExPwned or you can implement your own client. To use ExPwned, add it to your mix.exs

Usage

Use in a function to validate changesets.

  def changeset(user, attrs) do
    user
    |> ExNist.validate_repetitive_chars(:password)
    |> ExNist.validate_sequential_chars(:password)
    |> ExNist.validate_context_specific_words(:password, ["name_of_app"])
    |> ExNist.validate_derivative_words(:password, ["name_of_app"])
    |> ExNist.validate_dictionary_words(:password)
    |> ExNist.validate_password_breach(:password)
  end

The validation_* functions accept an optional :message argument to customize the error message.

Docs

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/ex_nist.

Link to this section Summary

Functions

Validate a changeset field for the use of context specific words. E.g. supply a list with words containing the username and the application name.

Validate a changeset field for the use of derivative words of a supplied list of words. E.g. supply a list with words containing the username and the application name.

Validate a changeset field for the use of common words in a dictionary file.

Validate a changeset field for the use of common words in a dictionary file.

Validate a changeset field for the use of repetitive characters

Validate a changeset field for the use of sequences

Link to this section Functions

Link to this function

validate_context_specific_words(changeset, field, opts \\ [])

View Source

Validate a changeset field for the use of context specific words. E.g. supply a list with words containing the username and the application name.

Examples

iex> ExNist.validate_context_specific_words(build_changeset("abc"), :password, words: ["abc"])
#Ecto.Changeset<action: nil, changes: %{password: "abc"}, errors: [password: {"This password contains disallowed words", []}], data: %{}, valid?: false>

iex> ExNist.validate_context_specific_words(build_changeset("aab"), :password, words: ["abc"])
#Ecto.Changeset<action: nil, changes: %{password: "aab"}, errors: [], data: %{}, valid?: true>
Link to this function

validate_derivative_words(changeset, field, opts \\ [])

View Source

Validate a changeset field for the use of derivative words of a supplied list of words. E.g. supply a list with words containing the username and the application name.

Examples

iex> ExNist.validate_derivative_words(build_changeset("abc"), :password, words: ["bbc"])
#Ecto.Changeset<action: nil, changes: %{password: "abc"}, errors: [password: {"This password contains derivative disallowed words", [word: "bbc"]}], data: %{}, valid?: false>

iex> ExNist.validate_derivative_words(build_changeset("abcdef"), :password, words: ["bbcdef"], similarity_percentage: 0.90)
#Ecto.Changeset<action: nil, changes: %{password: "abcdef"}, errors: [], data: %{}, valid?: true>

iex> ExNist.validate_derivative_words(build_changeset("aab"), :password, words: ["abc"])
#Ecto.Changeset<action: nil, changes: %{password: "aab"}, errors: [], data: %{}, valid?: true>
Link to this function

validate_dictionary_words(changeset, field, opts \\ [])

View Source

Validate a changeset field for the use of common words in a dictionary file.

Examples

iex> ExNist.validate_dictionary_words(build_changeset("Baker"), :password, words: ["bbc"])
#Ecto.Changeset<action: nil, changes: %{password: "Baker"}, errors: [password: {"This password contains disallowed words", [word: "baker"]}], data: %{}, valid?: false>

iex> ExNist.validate_dictionary_words(build_changeset("abcdef"), :password, words: ["bbcdef"])
#Ecto.Changeset<action: nil, changes: %{password: "abcdef"}, errors: [], data: %{}, valid?: true>
Link to this function

validate_password_breach(changeset, field, opts \\ [])

View Source

Validate a changeset field for the use of common words in a dictionary file.

The opts accepts :password_breach_client , it defaults to ExNist.PasswordBreachClient.ExPwned but can be another module that implements the ExNist.PasswordBreachClient behaviour.

Examples

ExNist.validate_password_breach(build_changeset("secret"), :password)
#Ecto.Changeset<action: nil, changes: %{password: "Baker"}, errors: [password: {"This password has appeared in a data breach.", [num_breaches: 5]}], data: %{}, valid?: false>

ExNist.validate_password_breach(build_changeset("lkjlkjsda2dfs9234"), :password)
#Ecto.Changeset<action: nil, changes: %{password: "abcdef"}, errors: [], data: %{}, valid?: true>
Link to this function

validate_repetitive_chars(changeset, field, opts \\ [])

View Source

Validate a changeset field for the use of repetitive characters

Examples

iex> ExNist.validate_repetitive_chars(build_changeset("aaab"), :password)
#Ecto.Changeset<action: nil, changes: %{password: "aaab"}, errors: [password: {"This password has the same character repeated", [validation: :repeated_character]}], data: %{}, valid?: false>

iex> ExNist.validate_repetitive_chars(build_changeset("aab"), :password)
#Ecto.Changeset<action: nil, changes: %{password: "aab"}, errors: [], data: %{}, valid?: true>
Link to this function

validate_sequential_chars(changeset, field, opts \\ [])

View Source

Validate a changeset field for the use of sequences

Examples

iex> ExNist.validate_sequential_chars(build_changeset("abc"), :password)
#Ecto.Changeset<action: nil, changes: %{password: "abc"}, errors: [password: {"This password contains a sequence (e.g. abc or 123)", []}], data: %{}, valid?: false>

iex> ExNist.validate_sequential_chars(build_changeset("aab"), :password)
#Ecto.Changeset<action: nil, changes: %{password: "aab"}, errors: [], data: %{}, valid?: true>