Limitar los intentos de contraseña en Linux no es solo una manía de administradores paranoicos; es una de las medidas más efectivas para frenar ataques de fuerza bruta y accesos no autorizados, tanto en entornos de escritorio como en servidores. A poco que tu equipo contenga información sensible o se conecte a Internet, te interesa dejar bien atada esta parte del sistema y auditar tu red local.
Además de poner una contraseña robusta, configurar bloqueos temporales o definitivos tras varios fallos es clave: ralentiza a los atacantes, genera más registros (logs) para auditoría y te permite combinar esta protección con otras políticas de contraseñas (caducidad, complejidad, reutilización, etc.). Vamos a ver, con calma pero al detalle, cómo se hace en distintas distribuciones y en diferentes niveles del sistema.
Bloqueo de cuentas por intentos fallidos en RedHat, CentOS y derivados
En las distribuciones basadas en RedHat (RHEL, CentOS, Rocky, AlmaLinux…), el bloqueo de cuentas por intentos fallidos se gestiona con el módulo PAM pam_faillock. Este módulo controla cuántos intentos erróneos se permiten, durante cuánto tiempo se bloquea la cuenta y qué usuarios se ven afectados (incluyendo, si quieres, al propio root).
Para aplicar esta política hay que editar los ficheros de PAM globales, normalmente /etc/pam.d/system-auth y, en algunas versiones, también /etc/pam.d/password-auth. Estos ficheros actúan como plantillas para la mayoría de servicios de autenticación en el sistema (login en consola, sudo, SSH, etc.).
En esos archivos se añaden líneas similares a estas, dentro de la sección de auth y account:
auth required pam_faillock.so preauth silent audit deny=2 unlock_time=120
auth pam_faillock.so authfail audit deny=2 unlock_time=120
account required pam_faillock.so
La primera línea actúa antes de la autenticación real (preauth), la segunda se ejecuta cuando la autenticación falla y la tercera se encarga de comprobar el estado de bloqueo de la cuenta en la fase de account. Modificando los parámetros puedes ajustar la política a tus necesidades.
Los parámetros más habituales de pam_faillock son:
- audit: habilita el registro detallado de los intentos de inicio de sesión, de forma que queden trazas en los logs del sistema (por ejemplo, en /var/log/secure).
- deny=2: establece el número máximo de intentos de contraseña fallidos antes de bloquear la cuenta. En este ejemplo son 2, pero puedes subirlo (3, 5, 10…).
- unlock_time=120: indica el tiempo de bloqueo en segundos. Aquí serían 120 segundos (2 minutos) hasta que la cuenta vuelve a estar operativa automáticamente.
- silent: si está presente, no muestra al usuario que ha sido bloqueado; simplemente deja de aceptar inicios de sesión, lo que hace el sistema menos “verboso” de cara a un atacante.
Un detalle importante es que, por defecto, root queda fuera de este bloqueo. Si quieres que también se le apliquen las mismas reglas, es necesario añadir el parámetro even_deny_root en las líneas de pam_faillock de la sección auth. Esto endurece la seguridad, pero debes valorar el riesgo de dejarte sin acceso si te equivocas demasiadas veces.
Cuando una cuenta está bloqueada y no usas el parámetro silent, el sistema puede mostrar mensajes explícitos advirtiendo de que el usuario ha superado el número de intentos permitidos. Esto es útil en entornos de pruebas para verificar la configuración, aunque en producción suele ser mejor no dar demasiada información.
Para ver los intentos fallidos de un usuario concreto, en sistemas RedHat puedes usar el comando faillock apuntando a la cuenta que te interesa:
faillock --user lionel
Este comando muestra cuántos intentos fallidos lleva acumulados el usuario, desde qué IP en caso de SSH y otros detalles relevantes para la auditoría. Además, siempre puedes revisar lo que aparece en /var/log/secure, donde se irán anotando estos eventos de seguridad.

Bloqueo de cuentas por intentos fallidos en Debian y Ubuntu
En el caso de Debian, Ubuntu y derivados, la lógica es similar pero cambia el módulo PAM utilizado. Tradicionalmente se ha usado pam_tally2 para contar intentos fallidos y bloquear cuentas automáticamente, aunque en versiones modernas se recomienda migrar a pam_faillock. Aun así, pam_tally2 sigue muy presente en muchas guías y entornos.
Para aplicar un bloqueo por número de intentos fallidos en Debian típico, se suele editar el archivo /etc/pam.d/common-auth, que define la política estándar de autenticación para la mayoría de servicios locales. En él puedes añadir una línea como esta:
auth required pam_tally2.so onerr=fail deny=3 unlock_time=120 audit even_deny_root root_unlock_time=600
Con esta configuración, el sistema bloquea la cuenta tras 3 intentos fallidos, mantiene el bloqueo durante 120 segundos para usuarios normales y durante 600 segundos para root. Además, si ocurre algún error con el módulo (onerr=fail), por seguridad se deniega el acceso en lugar de permitirlo.
Los parámetros principales de pam_tally2 son:
- onerr=fail: si hay un problema al leer o actualizar el contador de intentos, se deniega la autenticación para no dejar una puerta abierta por error.
- deny=3: número máximo de intentos fallidos permitidos antes de bloquear la cuenta. El valor 3 suele ser bastante razonable en la práctica.
- unlock_time=120: tiempo en segundos que la cuenta permanecerá bloqueada para usuarios estándar.
- audit: registra la información de fallos de autenticación en los logs (en Debian, lo habitual es /var/log/auth.log).
- even_deny_root: fuerza a que root también cuente en este sistema de bloqueo, algo que conviene usar con precaución.
- root_unlock_time=600: tiempo de bloqueo específico para la cuenta root, en segundos, independiente del resto de usuarios.
Al activarse el bloqueo, el usuario verá un mensaje indicando que su cuenta ha sido deshabilitada temporalmente por demasiados intentos fallidos. Esto permite al administrador detectar comportamientos sospechosos y al propio usuario darse cuenta de que algo no va bien.
Para consultar los intentos fallidos registrados por pam_tally2 para un usuario concreto (por ejemplo, lionel), se puede utilizar:
pam_tally2 -u lionel
Este comando muestra el número de fallos acumulados y permite, con opciones adicionales, reiniciar el contador de forma manual si fuera necesario. Además, al igual que en RedHat, siempre tienes la opción de revisar /var/log/auth.log para ver con más detalle qué ha ocurrido en cada intento de autenticación.
Limitar intentos en SSH con MaxAuthTries
Una de las puertas de entrada más habituales en servidores Linux es SSH, y por eso es crítico controlar cuántos intentos de autenticación se permiten por conexión. Aquí entra en juego la directiva MaxAuthTries, que se configura en el archivo /etc/ssh/sshd_config del servidor OpenSSH.
La idea es sencilla: MaxAuthTries define el número máximo de intentos de autenticación permitidos por conexión SSH. Si se supera, el servidor corta la conexión, obligando al atacante a iniciar una nueva sesión para seguir probando combinaciones, lo que frena bastante los ataques de fuerza bruta automatizados.
Para configurarlo, basta con editar el archivo de configuración:
sudo nano /etc/ssh/sshd_config
Después, localiza o añade una línea como esta:
MaxAuthTries 3
Con este valor, solo se permiten tres intentos de autenticación por conexión SSH. Si el usuario se equivoca más veces, el demonio sshd cierra la sesión. Para que el cambio se aplique, hay que recargar o reiniciar el servicio, por ejemplo con:
sudo systemctl restart sshd
MaxAuthTries no sustituye a los módulos PAM como pam_tally2 o pam_faillock, sino que trabaja en paralelo. El servidor SSH controla a cuántos intentos seguidos permite llegar en una misma sesión, mientras PAM lleva el conteo global por usuario y puede bloquear su cuenta a nivel de sistema.
Además de MaxAuthTries, conviene combinar otras medidas de seguridad en SSH para hacer el servicio mucho más resistente:
- Cambiar el puerto por defecto: dejar de usar el puerto 22 y mover SSH a otro puerto menos obvio ayuda a filtrar muchos escaneos automáticos básicos.
- Usar claves públicas en lugar de solo contraseña: la autenticación mediante claves SSH elimina el problema de contraseñas débiles y es mucho más robusta frente a ataques de fuerza bruta.
- Restringir orígenes mediante firewall o configurar una DMZ: permitir SSH solo desde direcciones IP o rangos de red concretos añade una barrera muy efectiva a nivel de red.
Limitar intentos en la autenticación local con PAM
Más allá de SSH, la autenticación local (consola, TTYs, sudo, display manager gráfico) también se gestiona con PAM. En Debian y Ubuntu, por ejemplo, el archivo /etc/pam.d/common-auth es el corazón de esta configuración, y en sistemas RedHat su papel lo juega system-auth (y a veces password-auth).
Además de los módulos específicos de bloqueo como pam_faillock o pam_tally2, algunas distribuciones permiten limitar intentos y tiempos de login directamente mediante login.defs. En este archivo, situado en /etc/login.defs, se declaran valores como:
- LOGIN_RETRIES: número máximo de reintentos permitidos en el prompt de login antes de abortar el proceso.
- LOGIN_TIMEOUT: tiempo máximo, en segundos, que se permite mantener la sesión de login esperando entrada del usuario.
Por ejemplo, si ajustas LOGIN_RETRIES a 3, un usuario solo tendrá tres oportunidades de introducir su contraseña en una misma sesión de login antes de que el sistema cierre esa tentativa, obligándole a volver a iniciar el proceso. No bloquea la cuenta como tal, pero sí limita los intentos por sesión.
En el mismo archivo login.defs puedes ajustar también otros parámetros de seguridad relevantes, como:
- PASS_MAX_DAYS: días máximos que puede usarse una contraseña antes de obligar a cambiarla.
- PASS_MIN_DAYS: días mínimos entre cambios de contraseña, para evitar cambios demasiado frecuentes y “en cadena”.
- PASS_WARN_AGE: días de aviso antes de que la contraseña caduque, para que el usuario tenga margen de reacción.
- PASS_MIN_LEN y PASS_MAX_LEN: longitud mínima y máxima de la contraseña.
- PASS_ALWAYS_WARN: avisa cuando la contraseña no cumple determinados criterios de robustez.
- PASS_CHANGE_TRIES: número máximo de intentos de cambio de contraseña si la nueva clave se considera demasiado sencilla.
- ENCRYPT_METHOD: algoritmo de hash a utilizar para las contraseñas (lo habitual hoy es SHA-512, indicado como $6$).
Estas directivas afectan sobre todo a nuevos usuarios creados después de ajustar login.defs, por lo que es una manera cómoda de establecer una política base para toda la organización.
Gestión de intentos y caducidad con /etc/shadow y el comando chage
El fichero /etc/shadow es donde el sistema almacena las contraseñas cifradas de los usuarios locales, junto con toda la información de caducidad. Aunque no se cambian a mano en el día a día, entender su estructura ayuda mucho a auditar y afinar políticas de seguridad.
En cada línea de /etc/shadow aparecen varios campos separados por dos puntos. Los más relevantes para nuestras políticas son:
- Nombre de usuario: identifica la cuenta a la que pertenecen el resto de campos.
- Contraseña cifrada: se almacena como $id$salt$hashed, donde $id$ indica el algoritmo ($1$ MD5, $2a$/$2y$ Blowfish, $5$ SHA-256, $6$ SHA-512), seguido de la sal y el hash.
- Último cambio de contraseña: número de días desde el 1 de enero de 1970 (epoch) en que se modificó por última vez.
- Días mínimos y máximos de uso: controlan cuándo se puede volver a cambiar la contraseña y cuándo caduca.
- Días de aviso de caducidad: a partir de cuántos días antes de expirar empieza a avisar al usuario.
- Días de inactividad: una vez caducada la contraseña, cuánto tiempo pasa antes de deshabilitar completamente la cuenta.
- Fecha absoluta de expiración de la cuenta: también en formato de días desde 1970, marca el momento en que ya no se permite el login para ese usuario.
Para gestionar estos parámetros sin tocar directamente /etc/shadow se utiliza el comando chage (change age), que permite ajustar la caducidad de contraseña y cuenta para usuarios concretos.
Algunas opciones habituales de chage son:
- -d, –lastday: fija el día del último cambio de contraseña (en formato de días desde epoch o con una fecha legible).
- -E, –expiredate: establece la fecha a partir de la cual la cuenta caduca.
- -I, –inactive: marca la cuenta como inactiva tras un número de días desde la caducidad de la contraseña.
- -m, –mindays: define los días mínimos entre cambios de contraseña.
- -M, –maxdays: indica el número máximo de días durante los que la contraseña sigue siendo válida.
- -W, –warndays: fija cuántos días antes de la caducidad empezará a avisar.
- -l, –list: muestra el estado actual de caducidad de un usuario.
Por ejemplo, para consultar la información de caducidad del usuario pepe se puede ejecutar:
chage -l pepe
La salida indicará la fecha del último cambio, si la contraseña expira o no, la inactividad y los días mínimos y máximos, entre otros datos. Con esta herramienta puedes aplicar políticas de forma nominal, usuario por usuario, o en scripts que procesen grupos completos de cuentas.
Políticas de complejidad de contraseñas con pam_cracklib y pam_pwquality
Limitar intentos de contraseña está muy bien, pero si las contraseñas son del estilo “123456” o “qwerty”, poco vas a conseguir. Por eso es crucial forzar contraseñas robustas mediante módulos PAM como pam_cracklib y, en versiones más actuales, pam_pwquality.
El módulo pam_pwquality es una evolución de cracklib, y se integra con librerías como libpwquality para verificar que las contraseñas no estén en diccionarios, no sean demasiado cortas, ni repitan patrones simples o datos personales del usuario. En entornos basados en RHEL se incluye de forma nativa y en Debian/Ubuntu se puede instalar con paquetes como libpam-cracklib y libpam-pwquality.
Una vez instalado, la configuración principal se suele hacer en el fichero /etc/security/pwquality.conf, donde puedes definir parámetros de complejidad como:
- difok: número de caracteres que deben ser diferentes respecto a la contraseña anterior.
- minlen: longitud mínima aceptable para la nueva contraseña.
- dcredit, ucredit, lcredit, ocredit: créditos por incluir dígitos, mayúsculas, minúsculas y otros caracteres.
- minclass: número mínimo de clases de caracteres distintas necesarias (minúsculas, mayúsculas, dígitos, símbolos).
- maxrepeat: máximo de caracteres idénticos consecutivos permitidos.
- maxclassrepeat: máximo de caracteres consecutivos de la misma clase.
- gecoscheck: comprueba que la contraseña no contenga palabras del campo GECOS (comentario) del usuario en /etc/passwd.
- dictpath: ruta al diccionario utilizado para comprobar si una contraseña forma parte de una palabra conocida.
- badwords: listado de palabras que se vetan explícitamente.
El sistema de créditos es especialmente flexible. Básicamente, una contraseña gana créditos por incluir diversidad de caracteres; esos créditos pueden compensar una longitud algo menor. Por ejemplo, con minlen=10 y dcredit=2, una contraseña de 8 caracteres con 2 dígitos podría pasar el filtro porque suma 2 créditos adicionales. En cambio, si defines créditos negativos, obligas a que haya al menos un carácter de ese tipo (por ejemplo, dcredit=-1 exige al menos un dígito sí o sí).
Con minclass puedes requerir que la contraseña incluya varias clases distintas. Un valor de 2 fuerza, por ejemplo, a combinar letras y números, o letras y símbolos, etc. Un minclass=4 obligaría a utilizar minúsculas, mayúsculas, dígitos y caracteres especiales al mismo tiempo, algo muy típico en políticas corporativas exigentes.
Herramientas como pwscore permiten probar la robustez de una contraseña frente a las políticas definidas. Al pasar una contraseña por pwscore, éste te indica si la clave supera los requisitos o no y, en caso contrario, qué regla está incumpliendo (longitud insuficiente, demasiado simple, demasiado parecida a la anterior, etc.).
Configurar políticas robustas en Debian y Ubuntu con pam_cracklib
En sistemas Debian/Ubuntu es muy habitual utilizar pam_cracklib (o pwquality a través de PAM) para reforzar la política de contraseñas. El archivo clave aquí es /etc/pam.d/common-password, que define cómo se gestionan los cambios de contraseña para los usuarios del sistema.
Antes de tocar nada, es buena práctica hacer una copia de seguridad del fichero:
sudo cp /etc/pam.d/common-password /root/
Después, puedes editarlo con tu editor de texto favorito (nano, vim, etc.) con privilegios de superusuario. Dentro encontrarás una línea similar a:
password requisite pam_cracklib.so retry=3 minlen=8 difok=3
Aquí se definen parámetros como:
- retry: número de intentos que se permiten al usuario cuando está cambiando su contraseña, antes de que el cambio falle.
- minlen: longitud mínima de la contraseña.
- difok: número de caracteres que deben ser diferentes respecto a la contraseña anterior.
- ucredit, lcredit, dcredit, ocredit: créditos positivos o negativos para mayúsculas, minúsculas, dígitos y otros caracteres.
Por ejemplo, una política bastante exigente podría ser:
password requisite pam_cracklib.so retry=3 minlen=12 difok=3 ucredit=-3 lcredit=-3 dcredit=-3 ocredit=-3
Con esta configuración, toda nueva contraseña debe tener al menos 12 caracteres, diferir en al menos 3 caracteres de la anterior y contener como mínimo 3 mayúsculas, 3 minúsculas, 3 dígitos y 3 símbolos. Es una política muy dura, pero extremadamente eficaz contra contraseñas triviales.
Una vez modificada la política, puedes probarla cambiando tu propia contraseña con:
sudo passwd
Si la clave no cumple los requisitos, el sistema mostrará mensajes indicando el motivo: demasiado corta, parecida a una palabra del diccionario, repetición excesiva de caracteres, etc. Cuando la contraseña encaje con la política, el cambio se aplicará sin problemas.
Además de endurecer la política para nuevos cambios, Debian y Ubuntu permiten forzar a usuarios existentes a cambiar su contraseña para adaptarse a las nuevas reglas. Con el comando:
passwd -e USUARIO
se marca la contraseña de ese usuario como expirada, y en el siguiente inicio de sesión se le obligará a establecer una nueva clave que cumpla la política actual. También puedes controlar la caducidad global con:
passwd -w 5 -x 30 USUARIO
donde -x 30 establece una validez máxima de 30 días para la contraseña y -w 5 hace que el sistema empiece a avisar 5 días antes de la caducidad. Si añades -i 1:
passwd -w 5 -x 30 -i 1 USUARIO
la cuenta se marcará como inactiva si el usuario no cambia su contraseña un día después de que haya expirado, obligando a la intervención del administrador para reactivarla.
Aunque durante años se ha recomendado rotar contraseñas con mucha frecuencia, las guías modernas de seguridad (como las del NIST) matizan esta práctica: es preferible apostar por contraseñas largas y complejas, y por sistemas de doble factor de autenticación, antes que obligar a cambios demasiado frecuentes que acaben generando claves predecibles.
Configurar de forma cuidadosa los módulos PAM (pam_faillock, pam_tally2, pam_cracklib, pam_pwquality), los archivos clave como /etc/pam.d/common-auth, /etc/pam.d/common-password, /etc/login.defs, /etc/ssh/sshd_config y entender cómo se reflejan esas decisiones en /etc/shadow, marca la diferencia entre un sistema “de serie” y un entorno realmente endurecido frente a accesos indebidos y ataques de fuerza bruta.
