ex_nist v1.0.0 ExNist View Source
Set of Ecto.Changeset functions to validate against NIST guidelines.
Modeled after laravel-nist-password-rules
Recommendation | Implementation |
---|---|
[...] at least 8 characters in length | Provided by standard Ecto.Changeset validation function |
Passwords obtained from previous breach corpuses | The 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 words | The 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 username | The ExNist.validate_context_specific_words/3 rule checks the password does not contain the provided list of words. |
Context-specific words, [...] and derivatives thereof | The 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
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>
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>
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>
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>
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>
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>