- Linux permite limitar intentos de login y bloquear cuentas usando módulos PAM como pam_faillock y pam_tally2, según la distribución.
- SSH añade protección con MaxAuthTries, reduciendo la cantidad de intentos de autenticación por conexión sin bloquear la cuenta.
- Las políticas de contraseñas se completan con complejidad mínima, caducidad y control de reintentos mediante pam_cracklib, pam_pwquality y login.defs.
- Una buena combinación de estas medidas reduce ataques de fuerza bruta y mejora la seguridad sin comprometer la operatividad del sistema.
Controlar cuántas veces se puede fallar una contraseña en Linux es una de esas medidas de seguridad que casi siempre se dejan para “más adelante”… hasta que un día ves miles de intentos fallidos en los logs o un usuario bloqueado sin saber por qué. Configurar bien estos límites no solo protege contra ataques de fuerza bruta, también te ayuda a evitar bloqueos absurdos o problemas en servicios críticos.
En Linux tenemos varias capas donde se puede limitar los intentos de autenticación: módulos PAM específicos como pam_faillock y pam_tally2, directivas del servidor SSH como MaxAuthTries, parámetros en /etc/login.defs y herramientas de política de contraseñas como pam_cracklib o pam_pwquality. Entender cómo encajan todas ellas es clave para montar una política coherente y evitar sorpresas.
Bloquear cuentas por intentos fallidos en Linux: visión general
La idea base es sencilla: limitar los intentos fallidos y bloquear temporal o permanentemente la cuenta cuando se supera ese umbral. La práctica se complica porque intervienen varios componentes: PAM, SSH, configuración de sistema y, según la distribución, módulos distintos.
En distribuciones tipo Red Hat (RHEL, CentOS, Rocky, Alma…) el enfoque moderno es usar el módulo pam_faillock, que registra los errores de autenticación y aplica bloqueos automatizados con tiempos de desbloqueo configurables.
En entornos basados en Debian y Ubuntu se ha utilizado tradicionalmente pam_tally2 para contar intentos fallidos y denegar logins a partir de un umbral. Aunque en versiones recientes se está migrando hacia faillock, en muchos servidores de producción pam_tally2 sigue siendo lo que realmente manda.
Además de PAM, el SSH demonio tiene su propia directiva MaxAuthTries, que limita cuántos intentos de autenticación se permiten por conexión. Esto no bloquea cuentas por sí mismo, pero sí reduce la capacidad de un atacante para probar credenciales en un solo canal SSH.
Por último, ficheros como /etc/login.defs y módulos de calidad de contraseña controlan aspectos como el número de reintentos al cambiar clave, complejidad mínima, caducidad o longitud, completando el “pack” de seguridad de cuentas.

Bloqueo de cuentas por intentos fallidos en Red Hat, CentOS y derivados (pam_faillock)
En el ecosistema Red Hat, el bloqueo por fallos de autenticación se gestiona con el módulo pam_faillock, que se integra en la pila PAM de forma centralizada. Este módulo se configura normalmente en los ficheros /etc/pam.d/system-auth y, en algunas versiones, también en /etc/pam.d/password-auth.
Para activar un bloqueo tras varios intentos fallidos se añaden líneas como estas en los bloques de auth y account de esos ficheros PAM (el detalle exacto puede variar según la versión, pero la idea es esta):
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
Estos parámetros marcan el comportamiento básico del bloqueo:
- audit: registra los intentos fallidos y bloqueos en los logs del sistema, normalmente en /var/log/secure o el journal.
- deny=2: bloquea la cuenta después de 2 intentos fallidos.
- unlock_time=120: la cuenta se desbloquea automáticamente tras 120 segundos (2 minutos).
- silent: oculta al usuario que la cuenta está bloqueada, lo que dificulta el trabajo a un atacante que prueba contraseñas a ciegas.
Un matiz importante: por defecto root suele quedar fuera de este bloqueo. Si quieres que también se apliquen límites a la cuenta de administración, hay que añadir el parámetro even_deny_root en las líneas de auth, asumiendo el riesgo de que un error de configuración te deje sin acceso si olvidas la contraseña o rompes SSH.
Cuando una cuenta se bloquea por pam_faillock, el usuario recibe un mensaje específico al intentar autenticarse si no usamos la opción silent. Esto ayuda a soporte a identificar rápidamente que no se trata de una contraseña cambiada, sino de un bloqueo temporal por demasiados fallos.
Para revisar los intentos fallidos y el estado de bloqueo de un usuario se utiliza la herramienta faillock en modo administrador:
# faillock --user lionel
El comando muestra cuántos intentos se han acumulado y desde qué IP o TTY, facilitando la investigación de intentos sospechosos. Y si necesitas liberar a un usuario sin esperar al unlock_time, basta con resetear su contador:
# faillock --user lionel --reset
También existe el fichero de configuración /etc/security/faillock.conf, donde se pueden definir parámetros globales sin tocar directamente los ficheros PAM, por ejemplo:
deny = 3
fail_interval = 600
unlock_time = 900
En este fichero puedes ajustar el número de intentos, la ventana de cómputo y el tiempo de bloqueo de forma más ordenada, centralizando la política sin ensuciar tanto las líneas PAM.
Bloqueo de cuentas en Debian y Ubuntu con pam_tally2
En sistemas Debian y Ubuntu clásicos, el módulo encargado de contar intentos fallidos es pam_tally2. Este módulo mantiene un fichero de recuento (por defecto /var/log/tallylog) donde guarda los fallos de autenticación por usuario.
Para activar una política de bloqueo por número de fallos se suele editar el fichero /etc/pam.d/common-auth y añadir una línea como:
auth required pam_tally2.so onerr=fail deny=3 unlock_time=120 audit even_deny_root root_unlock_time=600
La combinación de opciones permite afinar mucho el comportamiento:
- onerr=fail: si se produce un error en el módulo (por ejemplo, problema con tallylog), se niega el acceso por seguridad.
- deny=3: bloquea la cuenta tras 3 intentos fallidos.
- unlock_time=120: la cuenta se desbloquea automáticamente tras 120 segundos.
- audit: registra los eventos en /var/log/auth.log.
- even_deny_root: incluye al usuario root en la política de bloqueo.
- root_unlock_time=600: fija un tiempo de bloqueo distinto para root (por ejemplo 600 segundos) aunque unlock_time sea otro.
Cuando una cuenta queda bloqueada, el sistema muestra un mensaje específico indicando que el número máximo de intentos ha sido superado; así el usuario no sigue probando y el administrador sabe que el incidente no es un simple “me he olvidado de la clave”.
Para consultar el contador de intentos de un usuario concreto se emplea el programa pam_tally2 (sin .so) con el parámetro -u:
# pam_tally2 -u lionel
El comando muestra el número de fallos, si la cuenta está bloqueada y desde cuándo. Además, desde esta misma herramienta podemos resetear el contador añadiendo la opción –reset, lo que libera al usuario sin esperar a que pase el tiempo de bloqueo.
Los eventos asociados a pam_tally2 se registran normalmente en /var/log/auth.log, de modo que es fácil integrarlos en sistemas de monitorización o SIEM para disparar alertas cuando se detectan patrones anómalos de intentos fallidos.
Limitar intentos en SSH: MaxAuthTries y otras medidas
El servicio SSH es una de las puertas principales de entrada a un servidor Linux, así que conviene ponerle varios cerrojos. Uno de los más sencillos es la directiva MaxAuthTries del propio demonio SSH, pensada específicamente para limitar intentos fallidos en una misma conexión.
MaxAuthTries define cuántos intentos de autenticación se pueden realizar antes de que el servidor cierre la sesión SSH. No bloquea la cuenta, pero corta la conexión y obliga a reabrirla, lo que ralentiza mucho los ataques de fuerza bruta.
Para configurarlo hay que editar el archivo de configuración SSH (normalmente /etc/ssh/sshd_config) y ajustar la directiva:
MaxAuthTries 3
En muchos sistemas el valor por defecto suele ser 6, que para un servidor expuesto a Internet es bastante generoso. Reducirlo a 3 o incluso 2 hace que cada conexión permita muy pocos intentos antes de ser forzada a cerrarse.
Es importante entender que MaxAuthTries no sustituye a pam_faillock o pam_tally2: simplemente pone un límite por conexión, mientras que PAM lleva el control global por usuario y puede bloquear cuentas durante un tiempo.
Además de tocar MaxAuthTries, hay otras recomendaciones básicas de endurecimiento de SSH:
- Cambiar el puerto por defecto (22) a otro menos obvio, reduciendo el ruido de bots que escanean Internet.
- Usar autenticación por clave pública en lugar de contraseñas, o al menos obligar a claves para usuarios administrativos.
- Combinar SSH con firewall y listas blancas, permitiendo acceso solo desde IPs o rangos de confianza.
- Desactivar el login directo de root por SSH y obligar a usar sudo desde cuentas personales.
Si estás en Ubuntu y quieres reducir el número de veces que te pide la contraseña al iniciar sesión gráfica, jugar con MaxAuthTries en SSH no te va a solucionar nada: son mundos totalmente separados. En ese caso lo que manda es la pila PAM usada por el gestor de login (LightDM, GDM…), así que habría que revisar sus ficheros en /etc/pam.d, no sshd_config.
Políticas de contraseñas: complejidad, caducidad y número de reintentos
Limitar intentos fallidos está muy bien, pero si las contraseñas son “123456” o “qwerty” no vas a ir muy lejos. Una parte esencial del hardening en Linux consiste en definir una verdadera política de contraseñas que obligue a usar claves robustas y, cuando tenga sentido, a renovarlas periódicamente.
El objetivo de una buena política es impedir que los usuarios elijan claves previsibles o reutilizadas, forzando una combinación mínima de longitud, complejidad y cambio periódico razonable. Esto se aplica tanto a usuarios normales como a cuentas privilegiadas o cuentas de servicio críticas.
Los puntos clave de cualquier política de contraseñas decente en Linux suelen ser:
- Crear contraseñas robustas: longitud mínima (al menos 12 caracteres), mezcla de mayúsculas, minúsculas, dígitos y símbolos, y evitar palabras de diccionario.
- Evitar reutilización de contraseñas: no permitir que un usuario vuelva a una clave usada anteriormente.
- Establecer caducidad razonable: forzar el cambio cada cierto número de días, sin obsesionarse con rotaciones absurdamente frecuentes.
- Limitar los intentos al cambiar contraseña: impedir que un usuario se pase media hora probando claves débiles hasta que alguna cuele.
- Complementar con autenticación multifactor donde sea posible, sobre todo en accesos externos o paneles de administración.
En entornos corporativos estas políticas son imprescindibles para cumplir normativas, auditorías y estándares de seguridad. En servidores personales puede parecer exagerado, pero cuando alojas servicios accesibles desde Internet la diferencia entre una política seria y no tener nada es enorme.
Configurar políticas de contraseña con pam_cracklib y pam_pwquality
Los módulos PAM especializados en calidad de contraseñas permiten controlar al detalle cómo deben ser las claves. Históricamente se ha usado pam_cracklib, pero cada vez se ve más pam_pwquality, que añade mejoras y opciones adicionales.
En Debian y Ubuntu, el primer paso es instalar la librería correspondiente si no está ya presente:
sudo apt install libpam-cracklib libpam-pwquality libpwquality-tools
pam_cracklib se suele configurar desde /etc/pam.d/common-password. Lo habitual es tener una línea de este estilo:
password requisite pam_cracklib.so retry=3 minlen=12 difok=3 ucredit=-3 lcredit=-3 dcredit=-3 ocredit=-3
Cada parámetro controla un aspecto de la contraseña exigida:
- retry: número de intentos permitidos al usuario para introducir una contraseña válida antes de que el comando falle.
- minlen: longitud mínima de la contraseña.
- difok: número mínimo de caracteres distintos respecto a la contraseña anterior.
- ucredit: con valor negativo obliga a tener al menos esa cantidad de mayúsculas.
- lcredit: con valor negativo obliga a un mínimo de minúsculas.
- dcredit: con valor negativo exige un mínimo de dígitos.
- ocredit: con valor negativo impone un mínimo de símbolos u otros caracteres especiales.
Los créditos positivos funcionan como un sistema de “bonificación”: una contraseña puede ser un poco más corta si compensa con más complejidad en otras clases de caracteres. Los negativos, en cambio, marcan requisitos obligatorios: “como mínimo X mayúsculas”, etc.
pam_pwquality añade todavía más opciones, configuradas en /etc/security/pwquality.conf, donde se pueden ajustar parámetros como:
- difok: número de caracteres distintos respecto a la contraseña anterior.
- minlen: longitud mínima.
- dcredit, ucredit, lcredit, ocredit: créditos por tipos de caracteres, igual que en cracklib.
- minclass: número mínimo de clases diferentes (minúsculas, mayúsculas, dígitos, símbolos) requeridas.
- maxrepeat: máximo de caracteres repetidos consecutivamente.
- maxclassrepeat: máximo de caracteres consecutivos de la misma clase.
- gecoscheck: rechaza contraseñas que contengan datos del campo GECOS del usuario (nombre completo, etc.).
- dictpath: ruta a diccionarios para bloquear palabras demasiado obvias.
- badwords: lista específica de palabras prohibidas.
El módulo incluso puede detectar palíndromos, cambios triviales de mayúsculas/minúsculas o contraseñas casi idénticas a anteriores, evitando las típicas trampas de “añado un 1 al final y listo”.
Una herramienta muy útil que acompaña a pwquality es pwscore, que permite medir la calidad de una contraseña en base a la configuración actual:
# echo 123 | pwscore
Falló la comprobación de calidad de la contraseña:
La contraseña tiene menos de 8 caracteres
Con una contraseña realmente compleja, pwscore devuelve una puntuación alta, normalmente hasta 100, lo que sirve para validar que la política que has definido no es ni demasiado laxa ni imposible de cumplir.
Gestionar expiración y edad de contraseñas: chage, /etc/shadow y login.defs
Además de la complejidad, es habitual controlar cuánto tiempo puede durar una contraseña antes de exigir un cambio. En Linux, esta información se almacena en el fichero /etc/shadow y se gestiona cómodamente con el comando chage y las directivas de /etc/login.defs.
El fichero /etc/shadow guarda, por usuario, la contraseña cifrada y datos de caducidad. El campo de la contraseña se estructura como $id$salt$hash, donde id indica el algoritmo usado (por ejemplo, $6$ para SHA-512). Otros campos indican el último cambio de contraseña, días de validez, días de aviso antes de expirar, días de inactividad tras la caducidad, etc.
El comando chage permite consultar y modificar estos valores a nivel individual de usuario. Algunas opciones clave:
- -l: muestra la información de caducidad de la cuenta.
- -m: días mínimos entre cambios de contraseña.
- -M: días máximos que la contraseña es válida.
- -W: días de aviso antes de la caducidad.
- -E: fecha de expiración de la cuenta.
- -I: días de inactividad después de la caducidad antes de desactivar la cuenta.
Un ejemplo típico de consulta sería:
# chage -l pepe
Last password change : Apr 18, 2020
Password expires : never
Password inactive : never
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 90
Number of days of warning before password expires : 5
Para definir valores por defecto para nuevos usuarios se utiliza /etc/login.defs, donde se establecen directivas globales como:
- PASS_MAX_DAYS: días máximos que se puede usar una contraseña (por ejemplo, 90).
- PASS_MIN_DAYS: días mínimos entre cambios de contraseña.
- PASS_WARN_AGE: días de aviso previo a la caducidad.
- PASS_MIN_LEN y PASS_MAX_LEN: longitud mínima y máxima, aunque en la práctica se suele delegar esto en PAM.
- PASS_CHANGE_TRIES: cantidad máxima de intentos de cambio de contraseña si la clave es rechazada por débil.
- ENCRYPT_METHOD: algoritmo de hash usado (por ejemplo, SHA512).
- LOGIN_RETRIES: reintentos permitidos en el login antes de abortar.
- LOGIN_TIMEOUT: tiempo máximo en segundos para introducir credenciales.
Un detalle importante: las directivas de login.defs afectan a usuarios creados después de modificarlas. Las cuentas ya existentes conservan sus valores y hay que ajustarlas con chage si queremos que cumplan la nueva política.
Integrar límite de intentos con políticas de empresa y buenas prácticas
En entornos profesionales no basta con poner un par de parámetros y cruzar los dedos. Las políticas de contraseñas y de intentos fallidos deben estar alineadas con la realidad de la organización y con plataformas de identidad como Keycloak y con el impacto que tiene bloquear cuentas de servicio o de usuarios clave.
Por ejemplo, bloquear agresivamente una cuenta de servicio que ejecuta un proceso crítico puede dejar inoperativo un sistema entero si un script se queda en bucle probando credenciales erróneas. En estos casos hay que valorar si se excluye esa cuenta de los bloqueos o se implementan mecanismos alternativos de protección.
También hay que tener en cuenta las recomendaciones actuales de organismos como el NIST, que priorizan más la longitud y complejidad de la contraseña sobre la rotación forzosa demasiado frecuente. Forzar cambios cada 90 días suele ser razonable, pero hacerlo cada 30 puede terminar generando claves predecibles del tipo “Password01”, “Password02”, etc.
La formación de los usuarios es una pieza que muchas veces se olvida. Por muy buena que sea tu configuración de PAM, si la gente sigue escribiendo la contraseña en un post-it pegado al monitor, todo el esfuerzo se viene abajo. Explicar el porqué de las políticas ayuda a que se cumplan con menos resistencia.
Por último, la combinación de todas estas medidas con doble factor de autenticación donde sea viable (VPN, paneles, SSH con OTP, etc.) multiplica la seguridad sin depender tanto de que la contraseña sea perfecta.
Poniendo en conjunto límites de intentos de contraseña, bloqueos temporales, políticas de complejidad y caducidad razonables, y endureciendo el acceso SSH, se consigue un ecosistema mucho más resistente a ataques de fuerza bruta y errores humanos, sin convertir el día a día de los usuarios en una pesadilla imposible.
Redactor apasionado del mundo de los bytes y la tecnología en general. Me encanta compartir mis conocimientos a través de la escritura, y eso es lo que haré en este blog, mostrarte todo lo más interesante sobre gadgets, software, hardware, tendencias tecnológicas, y más. Mi objetivo es ayudarte a navegar por el mundo digital de forma sencilla y entretenida.
