La gestión de contraseñas es algo que no debería reinventarse innecesariamente, y Django se esfuerza por proporcionar un conjunto seguro y flexible de herramientas para gestionar las contraseñas de los usuarios. Este documento describe cómo Django almacena las contraseñas, cómo la configuración del almacenamiento de hash puede ser personalizada, y algunas utilidades para trabajar con contraseñas hash.
Ver también
Aunque los usuarios pueden utilizar contraseñas fuertes, los atacantes podrían poder echar un vistazo a sus conexiones. Utiliza HTTPS para evitar enviar contraseñas (o cualquier otro dato sensible) sobre conexiones HTTP planas porque estarán vulnerables al robo de contraseñas.
Django proporciona un sistema flexible de almacenamiento de contraseñas y utiliza PBKDF2 por defecto.
La contraseña del atributo password de un objeto User es una cadena en este formato:
<algorithm>$<iterations>$<salt>$<hash>
Los componentes utilizados para almacenar la contraseña de un usuario, separados por el carácter de dólar y consisten en: el algoritmo de hashing, el número de iteraciones del algoritmo (factor de trabajo), la sal aleatoria y la huella de contraseña resultante. El algoritmo es uno de varios algoritmos de hashing o almacenamiento de contraseñas que Django puede utilizar; consulte a continuación. Las iteraciones describen el número de veces que se ejecuta el algoritmo sobre la huella. La sal es la semilla aleatoria utilizada y la huella es el resultado de la función uno-a-uno.
Por defecto, Django utiliza el algoritmo PBKDF2 con un hash SHA256, una mecanismo de estiramiento de contraseñas recomendado por NIST. Esto debería ser suficiente para la mayoría de los usuarios: es bastante seguro y requiere grandes cantidades de tiempo de cómputo para romperlo.
Sin embargo, dependiendo de sus requisitos, puede elegir un algoritmo diferente o incluso utilizar un algoritmo personalizado para adaptarse a su situación de seguridad específica. De nuevo, la mayoría de los usuarios no necesitarán hacer esto – si no está seguro, probablemente no lo haga. Si lo hace, por favor continúa leyendo:
Django elige el algoritmo a utilizar consultando la configuración PASSWORD_HASHERS. Esta es una lista de clases de algoritmos de hashing que esta instalación de Django admite.
Para almacenar contraseñas, Django utilizará el primer hasher en PASSWORD_HASHERS. Para almacenar nuevas contraseñas con un algoritmo diferente, coloque su algoritmo preferido primero en PASSWORD_HASHERS.
Para verificar contraseñas, Django encontrará el hasher en la lista que coincida con el nombre del algoritmo en la contraseña almacenada. Si una contraseña almacenada menciona un algoritmo no encontrado en PASSWORD_HASHERS, intentar verificarla levantará ValueError.
El valor predeterminado de PASSWORD_HASHERS es:
PASSWORD_HASHERS = [
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
"django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
"django.contrib.auth.hashers.Argon2PasswordHasher",
"django.contrib.auth.hashers.BCryptSHA256PasswordHasher",
"django.contrib.auth.hashers.ScryptPasswordHasher",
]
Esto significa que Django utilizará PBKDF2 para almacenar todas las contraseñas pero apoyará la verificación de contraseñas almacenadas con PBKDF2SHA1, argon2 y bcrypt.
Las secciones siguientes describen un par de formas comunes en que los usuarios avanzados pueden modificar esta configuración.
Argon2 es el ganador de la competencia de 2015 Concurso de Hasheo de Contraseñas, una competencia organizada por la comunidad para seleccionar un algoritmo de hasheo de próxima generación. Está diseñado para no ser más fácil de calcular en hardware personalizado que en un procesador ordinario. La variante predeterminada del hasheador de contraseñas Argon2 es Argon2id.
Argon2 no es el predeterminado para Django porque requiere una biblioteca de terceros. El panel del Concurso de Hasheo de Contraseñas, sin embargo, recomienda el uso inmediato de Argon2 en lugar de los otros algoritmos admitidos por Django.
Para usar Argon2id como tu algoritmo de almacenamiento predeterminado, haz lo siguiente:
Instala la argon2-cffi paquete. Esto se puede hacer ejecutando python -m pip install django[argon2], que es equivalente a python -m pip install argon2-cffi (junto con cualquier requisito de versión desde el archivo pyproject.toml de Django).
Modifica PASSWORD_HASHERS para listar Argon2PasswordHasher primero. Es decir, en tu archivo de configuración, pondrías:
PASSWORD_HASHERS = [
"django.contrib.auth.hashers.Argon2PasswordHasher",
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
"django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
"django.contrib.auth.hashers.BCryptSHA256PasswordHasher",
"django.contrib.auth.hashers.ScryptPasswordHasher",
]
Mantén y/o agrega cualquier entrada en esta lista si necesitas que Django actualice las contraseñas.
bcrypt con Django¶Bcrypt es un algoritmo de almacenamiento de contraseñas popular diseñado específicamente para el almacenamiento a largo plazo de contraseñas. No es el utilizado por defecto por Django ya que requiere la utilización de bibliotecas de terceros, pero como muchos usuarios pueden querer utilizarlo, Django admite bcrypt con un mínimo de esfuerzo.
Para usar Bcrypt como tu algoritmo de almacenamiento predeterminado, haz lo siguiente:
Instala el paquete bcrypt . Esto se puede hacer ejecutando python -m pip install django[bcrypt], lo que es equivalente a python -m pip install bcrypt (junto con cualquier requisito de versión desde Django’s pyproject.toml).
Modifica PASSWORD_HASHERS para listar primero BCryptSHA256PasswordHasher . Es decir, en tu archivo de configuración, pondrías:
PASSWORD_HASHERS = [
"django.contrib.auth.hashers.BCryptSHA256PasswordHasher",
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
"django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
"django.contrib.auth.hashers.Argon2PasswordHasher",
"django.contrib.auth.hashers.ScryptPasswordHasher",
]
Mantén y/o agrega cualquier entrada en esta lista si necesitas que Django actualice las contraseñas.
Eso es todo – ahora tu instalación de Django utilizará Bcrypt como el algoritmo de almacenamiento por defecto.
scrypt con Django¶scrypt es similar a PBKDF2 y bcrypt en la utilización de un número fijo de iteraciones para ralentizar los ataques de fuerza bruta. Sin embargo, porque PBKDF2 y bcrypt no requieren una gran cantidad de memoria, los atacantes con suficientes recursos pueden lanzar grandes ataques paralelos para acelerar el proceso de ataque. scrypt está diseñado específicamente para utilizar más memoria que otras funciones de derivación de claves basadas en contraseñas para limitar la cantidad de paralelismo que un atacante puede usar, véase RFC 7914 para obtener más detalles.
Para utilizar scrypt como tu algoritmo de almacenamiento por defecto, haz lo siguiente:
Modifica PASSWORD_HASHERS para listar primero ScryptPasswordHasher . Es decir, en tu archivo de configuración:
PASSWORD_HASHERS = [
"django.contrib.auth.hashers.ScryptPasswordHasher",
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
"django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
"django.contrib.auth.hashers.Argon2PasswordHasher",
"django.contrib.auth.hashers.BCryptSHA256PasswordHasher",
]
Mantén y/o agrega cualquier entrada en esta lista si necesitas que Django actualice las contraseñas.
Nota
scrypt requiere OpenSSL 1.1+.
La mayoría de las contraseñas incluyen un sal junto con su hash de contraseña para protegerse contra ataques de tabla arcoiris. El sal en sí es un valor aleatorio que aumenta el tamaño y, por lo tanto, el costo de la tabla arcoiris y se establece actualmente en 128 bits con el salt_entropy valor en el BasePasswordHasher . A medida que disminuyen los costos de cómputo y almacenamiento, este valor debe aumentarse. Cuando implementes tu propio hash de contraseña, estás libre para sobreescribir este valor para utilizar un nivel de entropía deseado para tus hashes de contraseña. salt_entropy se mide en bits.
Detalles de implementación
Debido al método en que se almacenan los valores de sal, el valor salt_entropy es efectivamente un valor mínimo. Por ejemplo, un valor de 128 proporcionaría una sal que realmente contenga 131 bits de entropía.
El algoritmo PBKDF2 y bcrypt utilizan un número de iteraciones o rondas de hashing. Esto ralentiza deliberadamente a los atacantes, lo que hace que las ataques contra contraseñas hashadas sean más difíciles. Sin embargo, a medida que aumenta el poder de cálculo, es necesario aumentar el número de iteraciones. Hemos elegido un valor por defecto razonable (y lo aumentaremos con cada lanzamiento de Django), pero puede desear ajustarlo hacia arriba o hacia abajo, dependiendo de sus necesidades de seguridad y del poder de procesamiento disponible. Para hacerlo, deberá heredar el algoritmo apropiado y sobreescribir el parámetro iterations (utilice el parámetro rounds cuando herede un hashador bcrypt). Por ejemplo, para aumentar el número de iteraciones utilizadas por el algoritmo PBKDF2 predeterminado:
Crear una subclase de django.contrib.auth.hashers.PBKDF2PasswordHasher
from django.contrib.auth.hashers import PBKDF2PasswordHasher
class MyPBKDF2PasswordHasher(PBKDF2PasswordHasher):
"""
A subclass of PBKDF2PasswordHasher that uses 100 times more iterations.
"""
iterations = PBKDF2PasswordHasher.iterations * 100
Guarda esto en algún lugar de tu proyecto. Por ejemplo, podrías poner esto en un archivo como myproject/hashers.py.
Agrega tu nuevo hasheador como la primera entrada en PASSWORD_HASHERS:
PASSWORD_HASHERS = [
"myproject.hashers.MyPBKDF2PasswordHasher",
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
"django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
"django.contrib.auth.hashers.Argon2PasswordHasher",
"django.contrib.auth.hashers.BCryptSHA256PasswordHasher",
"django.contrib.auth.hashers.ScryptPasswordHasher",
]
Eso es todo – ahora tu instalación de Django utilizará más iteraciones cuando almacene contraseñas utilizando PBKDF2.
Nota
La traducción es:
Argon2 tiene las siguientes características que se pueden personalizar:
tiempo_coste controla el número de iteraciones dentro del hash.
coste_memoria controla el tamaño de memoria que debe utilizarse durante la computación del hash.
paralelismo controla cuántos CPUs se pueden paralelizar en la computación del hash.
Los valores predeterminados de estas características probablemente sean adecuados para ti. Si determinas que el hash de contraseña es demasiado rápido o demasiado lento, puedes ajustarlo de la siguiente manera:
Elige paralelismo como el número de hilos que puedes permitirte computar el hash.
Elige coste_memoria como los KiB de memoria que puedes permitirte.
Ajusta tiempo_coste y mide el tiempo que tarda en hashear una contraseña. Elige un tiempo_coste que te tome un tiempo aceptable. Si tiempo_coste configurado en 1 es demasiado lento, reduce coste_memoria.
Interpretación de coste_memoria
La traducción de los textos es la siguiente:
scrypt_ tiene las siguientes atributos personalizables:
work_factor controla el número de iteraciones dentro del hash.
block_size`
parallelism controla cuántos hilos correrán en paralelo.
maxmem limita el tamaño máximo de memoria que se puede utilizar durante la computación del hash. Por defecto es 0, lo que significa la restricción por defecto desde la biblioteca OpenSSL.
Hemos elegido valores razonables por defecto, pero puedes desear ajustarlos hacia arriba o hacia abajo según tus necesidades de seguridad y potencia de procesamiento disponible.
Estimar el uso de memoria
El requisito mínimo de memoria de scrypt_ es:
work_factor * 2 * block_size * 64
Los textos traducidos son:
Cuando los usuarios inician sesión, si sus contraseñas están almacenadas con cualquier algoritmo distinto del preferido, Django actualizará automáticamente el algoritmo a uno preferido. Esto significa que las instalaciones antiguas de Django se volverán más seguras automáticamente cuando los usuarios inicien sesión, y también significa que puede cambiar a nuevos (y mejores) algoritmos de almacenamiento a medida que se inventan.
Sin embargo, Django solo puede actualizar contraseñas que utilicen algoritmos mencionados en PASSWORD_HASHERS, por lo que al actualizar a sistemas nuevos debe asegurarse de nunca eliminar entradas de esta lista. Si lo hace, los usuarios que utilizan algoritmos no mencionados no podrán actualizar sus contraseñas. Las contraseñas cifradas se actualizarán cuando aumente (o disminuya) el número de iteraciones PBKDF2, rondas bcrypt o atributos argon2.
Ten en cuenta que si todas las contraseñas en su base de datos no están codificadas con el algoritmo del hashador predeterminado, puede estar vulnerable a un ataque de enumeración de usuarios debido a una diferencia entre la duración de una solicitud de inicio de sesión para un usuario con una contraseña codificada en un algoritmo no predeterminado y la duración de una solicitud de inicio de sesión para un usuario inexistente (que utiliza el hashador predeterminado). Puede poder mitigar esto mediante actualización de hashes de contraseñas antiguas.
Si tiene una base de datos existente con un hash antiguo y débil como MD5, puede querer actualizar esos hashes usted mismo en lugar de esperar a que la actualización suceda cuando un usuario inicia sesión (lo que puede no suceder si el usuario no regresa a su sitio). En este caso, puede utilizar un «hashador de contraseña envuelta».
Para este ejemplo, migraremos una colección de hashes MD5 para usar PBKDF2(MD5(password)) y agregaremos el hashador de contraseña correspondiente para verificar si el usuario ingresó la contraseña correcta al iniciar sesión. Suponemos que estamos utilizando el modelo de usuario integrado User y que nuestro proyecto tiene una aplicación accounts. Puede modificar el patrón para funcionar con cualquier algoritmo o con un modelo de usuario personalizado.
Primero, agregaremos el hashador personalizado:
accounts/hashers.py¶from django.contrib.auth.hashers import (
PBKDF2PasswordHasher,
MD5PasswordHasher,
)
class PBKDF2WrappedMD5PasswordHasher(PBKDF2PasswordHasher):
algorithm = "pbkdf2_wrapped_md5"
def encode_md5_hash(self, md5_hash, salt, iterations=None):
return super().encode(md5_hash, salt, iterations)
def encode(self, password, salt, iterations=None):
_, _, md5_hash = MD5PasswordHasher().encode(password, salt).split("$", 2)
return self.encode_md5_hash(md5_hash, salt, iterations)
La migración de datos podría verse algo así:
from django.db import migrations
from ..hashers import PBKDF2WrappedMD5PasswordHasher
def forwards_func(apps, schema_editor):
User = apps.get_model("auth", "User")
users = User.objects.filter(password__startswith="md5$")
hasher = PBKDF2WrappedMD5PasswordHasher()
for user in users:
algorithm, salt, md5_hash = user.password.split("$", 2)
user.password = hasher.encode_md5_hash(md5_hash, salt)
user.save(update_fields=["password"])
class Migration(migrations.Migration):
dependencies = [
("accounts", "0001_initial"),
# replace this with the latest migration in contrib.auth
("auth", "####_migration_name"),
]
operations = [
migrations.RunPython(forwards_func),
]
Ten en cuenta que esta migración tardará en el orden de varios minutos para varios miles de usuarios, dependiendo de la velocidad de tu hardware.
Finalmente, agregaremos la configuración de PASSWORD_HASHERS.
PASSWORD_HASHERS = [
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
"accounts.hashers.PBKDF2WrappedMD5PasswordHasher",
]
Incluye cualquier otro hasher que utilice su sitio en esta lista.
La lista completa de hasheadores incluidos en Django es:
[
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
"django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
"django.contrib.auth.hashers.Argon2PasswordHasher",
"django.contrib.auth.hashers.BCryptSHA256PasswordHasher",
"django.contrib.auth.hashers.BCryptPasswordHasher",
"django.contrib.auth.hashers.ScryptPasswordHasher",
"django.contrib.auth.hashers.MD5PasswordHasher",
]
El nombre correspondiente de los algoritmos es:
pbkdf2_sha256
pbkdf2_sha1
argon2
bcrypt_sha256
bcrypt
scrypt
md5
Si escribes tu propio hasheador de contraseña que contiene un factor de trabajo como un número de iteraciones, debes implementar un método harden_runtime(self, password, encoded) para cubrir la brecha de tiempo entre el factor de trabajo proporcionado en la contraseña codificada y el factor de trabajo por defecto del hasheador. Esto previene un ataque de enumeración de usuarios debido a la diferencia entre una solicitud de inicio de sesión para un usuario con una contraseña codificada en un número anterior de iteraciones y un usuario inexistente (que ejecuta el número por defecto de iteraciones del hasheador por defecto).
Tomando PBKDF2 como ejemplo, si encoded contiene 20.000 iteraciones y el hasheador por defecto tiene iterations de 30.000, el método debe pasar password a través de otras 10.000 iteraciones de PBKDF2.
Si tu hasheador no tiene un factor de trabajo, implementa el método como una acción nula (pass).
El módulo django.contrib.auth.hashers proporciona un conjunto de funciones para crear y validar contraseñas hashadas. Puedes utilizarlas independientemente del modelo User.
Versión asíncrona: acheck_password()
Si deseas autenticar manualmente a un usuario comparando una contraseña en texto plano con la contraseña hashada en la base de datos, utiliza la función conveniente check_password(). Esta función tiene dos argumentos obligatorios: la contraseña en texto plano para verificar y el valor completo del campo password de un usuario en la base de datos para verificar contra. Devuelve True si coinciden, False en caso contrario. Opcionalmente, puedes pasar un callable setter que tome la contraseña y se llamará cuando sea necesario regenerarla. También puedes pasar preferred para cambiar un algoritmo de hashing si no deseas utilizar el predeterminado (primera entrada del parámetro PASSWORD_HASHERS). Consulta Hashes incluidos para obtener el nombre del algoritmo de cada hasher.
Crea una contraseña hashada en el formato utilizado por esta aplicación. Tiene un argumento obligatorio: la contraseña en texto plano (cadena o bytes). Opcionalmente, puedes proporcionar un sal y un algoritmo de hashing para utilizar si no deseas utilizar los predeterminados (primera entrada del parámetro PASSWORD_HASHERS). Consulta Hashes incluidos para obtener el nombre del algoritmo de cada hasher. Si el argumento contraseña es None, se devuelve una contraseña inutilizable (una que nunca será aceptada por la función check_password()).
Devuelve False si la contraseña es un resultado de User.set_unusable_password().
Los usuarios a menudo eligen contraseñas pobres. Para ayudar a mitigar este problema, Django ofrece validadores de contraseñas pluggables. Puedes configurar múltiples validadores de contraseñas al mismo tiempo. Un par de validadores están incluidos en Django, pero también puedes escribir tus propios.
Cada validador de contraseña debe proporcionar un texto de ayuda para explicar los requisitos al usuario, validar una contraseña dada y devolver un mensaje de error si no cumple con los requisitos, y opcionalmente definir un callback para ser notificado cuando la contraseña de un usuario ha sido cambiada. Los validadores también pueden tener configuraciones opcionales para afinar su comportamiento.
La validación está controlada por el parámetro AUTH_PASSWORD_VALIDATORS. El valor predeterminado del parámetro es una lista vacía, lo que significa que no se aplican validadores. En proyectos nuevos creados con la plantilla de inicio predeterminada startproject, un conjunto de validadores está habilitado por defecto.
Por defecto, los validadores se utilizan en las formas para restablecer o cambiar contraseñas y en los comandos de gestión createsuperuser y changepassword. Los validadores no se aplican a nivel del modelo, por ejemplo en User.objects.create_user() y create_superuser(), porque asumimos que los desarrolladores, no los usuarios, interactúan con Django a ese nivel y también porque la validación de modelos no ejecuta automáticamente como parte de crear modelos.
Nota
La validación de contraseñas puede prevenir el uso de muchas tipos de contraseñas débiles. Sin embargo, el hecho de que una contraseña pase todos los validadores no garantiza que sea una contraseña fuerte. Hay muchos factores que pueden debilitar una contraseña que no se detectan ni siquiera por los validadores de contraseñas más avanzados.
La validación de contraseñas está configurada en la configuración AUTH_PASSWORD_VALIDATORS:
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
"OPTIONS": {
"min_length": 9,
},
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
Este ejemplo habilita los cuatro validadores incluidos:
UserAttributeSimilarityValidator, que verifica la similitud entre la contraseña y un conjunto de atributos del usuario.
MinimumLengthValidator, que verifica si la contraseña cumple con una longitud mínima. Este validador está configurado con una opción personalizada: ahora requiere una longitud mínima de nueve caracteres, en lugar de los ocho por defecto.
CommonPasswordValidator, que verifica si la contraseña aparece en una lista de contraseñas comunes. Por defecto, compara con una lista incluida de 20,000 contraseñas comunes.
NumericPasswordValidator, que verifica si la contraseña no es numérica en su totalidad.
Para UserAttributeSimilarityValidator y CommonPasswordValidator, estamos utilizando las configuraciones predeterminadas en este ejemplo. NumericPasswordValidator no tiene configuración.
Los textos de ayuda y cualquier error de los validadores de contraseñas se devuelven siempre en el orden en que están listados en AUTH_PASSWORD_VALIDATORS.
Django incluye cuatro validadores:
Valida que la contraseña tenga una longitud mínima. La longitud mínima se puede personalizar con el parámetro min_length.
Valida que la contraseña sea lo suficientemente diferente a ciertas atributos del usuario.
El parámetro user_attributes debería ser una iterable de nombres de atributos de usuario para comparar. Si no se proporciona este argumento, se utiliza el valor por defecto: 'username', 'first_name', 'last_name', 'email'. Los atributos que no existen son ignorados.
La similitud máxima permitida entre contraseñas se puede establecer en una escala de 0,1 a 1,0 con el parámetro max_similarity. Esto se compara con el resultado de difflib.SequenceMatcher.quick_ratio(). Un valor de 0,1 rechaza contraseñas a menos que sean sustancialmente diferentes del user_attributes, mientras que un valor de 1,0 rechaza solo las contraseñas que son idénticas al valor de un atributo.
Valida que la contraseña no sea una contraseña común. Esto convierte la contraseña a minúsculas (para hacer una comparación insensible al caso) y la compara contra una lista de 20,000 contraseñas comunes creadas por Royce Williams.
La traducción de los textos es la siguiente:
Hay algunas funciones en django.contrib.auth.password_validation que puedes llamar desde tus propias formas o código para integrar la validación de contraseñas. Esto puede resultar útil si utilizas formas personalizadas para establecer contraseñas, o si tienes llamadas a API que permiten establecer contraseñas, por ejemplo.
Valida una contraseña. Si todos los validadores encuentran válida la contraseña, devuelve None. Si uno o más validadores rechazan la contraseña, levanta un ValidationError con todos los mensajes de error de los validadores.
El objeto user es opcional: si no se proporciona, algunos validadores pueden no poder realizar ninguna validación y aceptar cualquier contraseña.
Los textos traducidos son:
Para subclases de AbstractBaseUser, el campo de contraseña será marcado como «dirty» cuando se llame a set_password() lo que desencadena una llamada a password_changed() después de que el usuario sea guardado.
Devuelve una lista de los textos de ayuda de todos los validadores. Estos explican las requisitos de contraseña al usuario.
Devuelve un string HTML con todos los textos de ayuda en un <ul>. Esto es útil cuando se agrega la validación de contraseña a formularios, ya que se puede pasar el resultado directamente al parámetro help_text de un campo de formulario.
Devuelve un conjunto de objetos de validador basado en el parámetro validator_config. Por defecto, todas las funciones utilizan los validadores definidos en AUTH_PASSWORD_VALIDATORS, pero llamando a esta función con un conjunto alternativo de validadores y luego pasando el resultado al parámetro password_validators de las otras funciones, su conjunto personalizado de validadores se utilizará en lugar de los predeterminados. Esto es útil cuando tienes un conjunto típico de validadores para usar en la mayoría de los escenarios, pero también tienes una situación especial que requiere un conjunto personalizado. Si siempre utilizas el mismo conjunto de validadores, no hay necesidad de utilizar esta función, ya que la configuración desde AUTH_PASSWORD_VALIDATORS se utiliza por defecto.
La estructura de validator_config es idéntica a la estructura de AUTH_PASSWORD_VALIDATORS. El valor de retorno de esta función puede ser pasado al parámetro password_validators de las funciones listadas anteriormente.
Ten en cuenta que donde la contraseña se pasa a una de estas funciones, esto debe siempre ser la contraseña en texto claro - no una contraseña hasheada.
Si los validadores integrados de Django no son suficientes, puedes escribir tus propios validadores de contraseñas. Los validadores tienen una interfaz bastante pequeña. Deben implementar dos métodos:
validate(self, password, user=None): valide una contraseña. Devuelve None si la contraseña es válida, o lanza un ValidationError con un mensaje de error si la contraseña no es válida. Debes poder manejar el caso en que user sea None - si eso significa que tu validador no puede ejecutarse, devuelve None para ningún error.
get_help_text(): proporcione un texto de ayuda para explicar los requisitos al usuario.
Cualquier elemento en OPTIONS en AUTH_PASSWORD_VALIDATORS para tu validador se pasará a la constructor. Todos los argumentos del constructor deben tener un valor por defecto.
Aquí tienes un ejemplo básico de un validador, con una configuración opcional:
from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _
class MinimumLengthValidator:
def __init__(self, min_length=8):
self.min_length = min_length
def validate(self, password, user=None):
if len(password) < self.min_length:
raise ValidationError(
_("This password must contain at least %(min_length)d characters."),
code="password_too_short",
params={"min_length": self.min_length},
)
def get_help_text(self):
return _(
"Your password must contain at least %(min_length)d characters."
% {"min_length": self.min_length}
)
También puedes implementar password_changed(password, user=None), que se llamará después de un cambio de contraseña exitoso. Eso puede usarse para evitar el reuso de contraseñas, por ejemplo. Sin embargo, si decides almacenar las contraseñas anteriores de los usuarios, nunca debes hacerlo en texto claro.
may 31, 2026