Ubuntu服务器安全加固:PAM模块配置密码策略与登录失败锁定 1. 项目概述为什么需要加固你的Ubuntu登录防线最近在帮几个朋友处理他们托管在云上的Ubuntu服务器发现一个挺普遍的现象很多人装完系统设个“123456”或者“admin”的密码就完事了SSH端口也默认开着22。这简直是把自家大门钥匙插在锁上还贴了张“欢迎光临”的纸条。其中一位的服务器甚至因为弱密码被暴力破解成了矿机收到云厂商的天价账单才慌了神。这件事让我觉得是时候系统性地聊聊Linux服务器特别是Ubuntu在登录安全上那些必须做的基础配置了。我们今天要聊的核心就两件事密码复杂度和连续登录失败处理。听起来可能有点枯燥像是运维手册里的条条框框但它们实际上是构筑服务器安全防线的第一道也是成本最低、效果最显著的“门卫”和“警报器”。密码复杂度策略决定了攻击者猜测你密码的难度是静态防御而连续登录失败处理比如账户锁定则是在攻击发生时动态响应直接掐断暴力破解的尝试是动态防御。两者结合才能有效应对从“撞库”到“暴力破解”的各种常见威胁。无论你是刚拥有第一台VPS的个人开发者还是需要维护中小规模集群的运维工程师这些配置都是你应该像“出门锁门”一样形成的肌肉记忆。下面我就结合最新的Ubuntu LTS版本如22.04, 24.04带你一步步把这些配置落到实处并解释清楚每一个参数背后的考量。2. 核心安全模块解析PAM与工具链在动手修改任何配置之前我们必须先理解幕后工作的核心机制——PAM。如果你直接去搜“如何修改密码策略”可能会找到一堆直接编辑/etc/pam.d/common-password的命令。但知其然更要知其所以然否则出了问题连排查方向都没有。2.1 PAM可插拔认证模块PAM 是 Linux 系统上处理身份认证的一套框架。你可以把它想象成一个高度模块化、可定制的“认证流水线”。当用户登录、切换身份如su、或修改密码时相关的程序如login,sshd,passwd并不会自己处理认证逻辑而是去调用 PAM。PAM 的配置文件通常位于/etc/pam.d/目录下每个需要认证的服务都有一个对应的文件。例如/etc/pam.d/sshd用于 SSH 登录认证/etc/pam.d/common-password则用于密码修改操作。这些配置文件由一系列“规则”组成每条规则定义了在认证的哪个阶段auth, account, password, session调用哪个模块以及模块的行为required, requisite, sufficient, optional。对于我们今天的主题密码复杂度主要由pam_pwquality(旧版叫pam_cracklib) 模块在password阶段控制。连续登录失败处理则通常由pam_tally2或pam_faillock模块在auth阶段控制。理解 PAM 是自由配置的前提它让你明白你的修改究竟作用于认证流程的哪一个环节。2.2 关键工具libpam-pwquality 与 pam_faillock在 Ubuntu 上实现我们所需的功能主要依赖两个包libpam-pwquality 这是设置密码复杂度策略的核心。它取代了旧的libpam-cracklib提供了更丰富和清晰的配置选项。它会检查新密码的长度、字符类别大小写字母、数字、特殊符号、是否在字典中、是否与旧密码太相似等。pam_faillock模块 这是处理连续登录失败的主流现代模块。它会在用户连续认证失败一定次数后临时锁定该用户的账户一段时间。它的状态信息失败次数默认存储在/var/run/faillock目录下是内存式的重启后清零。也可以配置为写入文件。注意在一些旧教程或 CentOS/RHEL 体系中你可能会看到pam_tally2。在 Ubuntu 22.04 及更新版本中pam_faillock是更推荐的方式它功能更强支持同时锁定本地和远程登录。安装与检查 在开始配置前先确保它们已安装。通常libpam-pwquality是默认安装的而pam_faillock可能需手动安装。# 检查 pwquality 是否安装 dpkg -l | grep libpam-pwquality # 安装 pam_faillock (如果未安装) sudo apt update sudo apt install libpam-faillock安装后你可以在/lib/x86_64-linux-gnu/security/或/lib/security/目录下找到对应的.so文件如pam_pwquality.so,pam_faillock.so这就是被 PAM 调用的模块。3. 密码复杂度策略深度配置密码策略的目标是强制用户设置一个强密码。我们通过配置libpam-pwquality来实现。主要配置文件有两个地方它们有优先级关系/etc/security/pwquality.conf 这是 pwquality 模块的主配置文件。在这里设置是全局生效的。PAM 配置文件中的模块参数 在/etc/pam.d/common-password文件中调用pam_pwquality.so时可以直接传递参数这里的设置会覆盖pwquality.conf。我个人的习惯是优先使用/etc/security/pwquality.conf因为它的配置集中、清晰并且有详细的注释说明每个参数的含义更适合管理和维护。3.1 解读与配置 pwquality.conf让我们打开这个文件看看里面有哪些可以调整的“旋钮”sudo vim /etc/security/pwquality.conf你会看到很多被注释掉的配置行格式是参数 值。我们来逐一解析几个最关键的核心参数minlen 12 这是密码的最小长度。这是最基础的防线。我强烈建议设置为至少12。长度是密码复杂度的首要因素。即使只使用小写字母一个12位随机密码的搜索空间也极其巨大。dcredit -1 要求密码中至少包含1位数字。-1表示“至少1个”-2表示“至少2个”正数则表示“最多给这么多分”但通常我们用负数来设置“至少”的要求。ucredit -1 要求密码中至少包含1个大写字母。lcredit -1 要求密码中至少包含1个小写字母。ocredit -1 要求密码中至少包含1个特殊符号如!#$%^*。minclass 4 这个参数非常有用它要求密码必须来自至少 N 种不同的字符类别数字、大写、小写、特殊。如果你设置了minclass3那么像Password123这样的密码有大写、小写、数字共3类就符合要求而password123只有小写和数字2类则不行。这比单独设置每个类别的数量更灵活能防止用户用“Password”后面简单加两个数字来应付。maxrepeat 3 允许同一个字符连续出现的最大次数。设置为3可以防止出现aaaB123!这样的密码。maxsequence 4 允许连续字符序列如abcd,1234的最大长度。防止使用键盘上的简单序列。dictcheck 1 是否检查密码是否基于字典中的单词。1为开启。这会调用系统字典防止使用apple2024这类弱密码。usercheck 1 是否检查密码中包含用户名正序或逆序。1为开启。防止用户使用自己的名字作为密码。retry 3 设置新密码时允许用户重试的次数。一个我推荐的配置示例# /etc/security/pwquality.conf minlen 12 minclass 3 dcredit -1 ucredit -1 lcredit -1 ocredit -1 maxrepeat 2 maxsequence 3 dictcheck 1 usercheck 1 retry 2 enforcing 1这个策略意味着密码至少12位必须包含数字、大写、小写、特殊符号中的至少3类且同一字符不能连续出现超过2次不能有超过3位的连续序列不能是字典词或包含用户名最多允许2次设置尝试。3.2 在PAM中启用并测试策略配置好pwquality.conf后需要确保 PAM 的密码修改流程调用了它。检查/etc/pam.d/common-password文件sudo cat /etc/pam.d/common-password | grep pwquality你应该会看到类似这样的一行password requisite pam_pwquality.so retry3如果存在并且没有try_first_pass或use_authtok等参数冲突它就会使用我们刚才在pwquality.conf里的配置。如果这一行被注释了取消注释即可。现在来测试一下为自己创建一个测试用户避免误操作影响当前用户sudo adduser testuser_complex切换到该用户并尝试修改密码sudo su - testuser_complex passwd尝试设置弱密码观察系统的拒绝信息。例如输入123456你会看到类似Bad password: too short的错误。输入Test123可能会看到Bad password: does not contain enough different characters或类别不足的提示。这些具体的错误信息正是pam_pwquality模块根据你的配置返回的是调试策略是否生效的直接依据。实操心得配置密码策略后务必自己先按策略要求设置一个强密码并成功登录一次。我曾经遇到过在配置了非常严格的策略后没有更新自己的密码结果某次登录缓存失效后因为密码不符合新策略而无法通过 PAM 认证把自己锁在了服务器外面。对于 root 用户或关键的管理员账户最好在配置前就先按照即将启用的策略修改好密码。4. 连续登录失败锁定策略实战密码策略是防“猜”而失败锁定是防“暴力试”。想象一下攻击者用自动化脚本以每秒数百次的速度尝试各种密码。失败锁定功能就是在探测到这种异常行为时临时“冻结”这个账户让攻击无法继续。4.1 配置 pam_faillock 模块如前所述我们使用pam_faillock。配置同样涉及两个文件/etc/security/faillock.conf 主配置文件如果不存在可以创建。PAM 配置文件 在/etc/pam.d/common-auth中插入该模块。首先编辑或创建/etc/security/faillock.confsudo vim /etc/security/faillock.conf写入以下核心配置# 账户在连续失败几次后被锁定 deny 5 # 锁定多长时间单位秒。21600秒6小时。也可以写成6h如果版本支持。 unlock_time 21600 # 在多久的时间窗口内计算失败次数单位秒。86400秒24小时。 fail_interval 86400 # 是否在达到失败次数时向系统日志(syslog)发送消息。 silent false # 是否在用户被锁定时显示提示信息。 audit true # 锁定的范围。user表示只锁单个用户host则锁整个主机针对该用户。一般用user。 scope user这个配置的意思是在24小时内如果同一个用户连续5次登录失败则该用户账户将被锁定6小时。在此期间即使输入了正确的密码认证也会失败。然后修改PAM配置。我们需要在认证栈的合适位置插入pam_faillock.so。编辑/etc/pam.d/common-authsudo vim /etc/pam.d/common-auth找到文件开头部分在auth required pam_deny.so这行之前添加如下两行auth required pam_faillock.so preauth silent audit deny5 unlock_time21600 auth [defaultdie] pam_faillock.so authfail audit deny5 unlock_time21600同时在auth required pam_deny.so这行之后添加auth sufficient pam_faillock.so authsucc audit deny5 unlock_time21600配置行解析preauth 在用户输入密码之前检查该用户是否已被锁定。authfail 当认证失败时增加失败计数。[defaultdie]表示如果这个模块失败即用户已被锁定或达到失败次数则立即终止认证流程不再继续后面的模块。authsucc 当认证成功时重置该用户的失败计数。sufficient表示如果认证成功这个模块的结果就足够了可以跳过后面的一些模块但不是全部PAM流程比较复杂。重要提示修改 PAM 配置是高风险操作。错误的配置可能导致所有用户包括root无法登录。强烈建议在修改前备份原文件并且确保你有一个可以通过“恢复模式”或云服务器控制台VNC访问的途径。4.2 测试失败锁定功能配置完成后需要测试是否生效。从另一个终端或另一台机器尝试SSH登录。使用一个存在的用户名比如刚才创建的testuser_complex但故意输入错误密码。连续错误5次后第6次即使输入了正确密码也应该会被拒绝并看到类似Account locked due to 5 failed logins的提示。查看失败记录sudo faillock --user testuser_complex这个命令会显示指定用户的登录失败记录、次数和锁定状态。手动解锁用户在锁定时间内如果需要恢复访问sudo faillock --user testuser_complex --reset这个命令会将该用户的失败计数清零立即解除锁定。4.3 针对root用户的特殊考量默认情况下上述配置对root 用户是否生效取决于 PAM 配置中的一个常见设置。在/etc/pam.d/common-auth文件中你可能会看到这样一行auth [success1 defaultignore] pam_unix.so nullok_secure或者在某些配置中会有针对root的特别规则。有些安全策略会刻意允许 root 不受失败锁定限制因为在高强度攻击下如果 root 被锁定且没有其他解锁途径如物理控制台可能导致系统完全无法管理造成更大的风险。我的建议是对于生产服务器禁止 root 用户直接通过 SSH 登录修改/etc/ssh/sshd_config中的PermitRootLogin no而是使用一个普通用户通过sudo来提权。这样失败锁定策略就应用在这个普通用户上即使它被锁定你还可以通过其他管理员账户或控制台去解锁避免了单点故障。这才是更安全的做法。5. 配置的持久化、验证与边界场景处理配置不是改完文件就万事大吉了。你需要验证它是否按预期工作并考虑一些边界情况。5.1 验证配置生效密码策略验证 使用passwd命令为测试用户设置密码尝试触发各种规则太短、太简单、无数字等确保错误信息与你配置的策略相符。失败锁定验证 如上节所述通过故意输错密码来触发锁定并使用faillock命令查看状态。检查系统日志 锁定事件和认证失败都会被记录。使用journalctl或查看/var/log/auth.log来确认。sudo tail -f /var/log/auth.log # 然后尝试一次失败登录观察日志输出你应该能看到包含pam_faillock和用户名的失败记录。5.2 配置的持久化与影响范围PAM配置的生效 PAM 配置是即时生效的。一旦你保存了/etc/pam.d/下的文件下一次认证请求就会使用新规则。无需重启服务。SSH服务 虽然 PAM 配置生效了但确保你的 SSH 服务sshd是启用了 PAM 的。检查/etc/ssh/sshd_config中是否有UsePAM yes。通常这是默认设置。修改 SSH 配置后需要重启服务sudo systemctl restart sshd。其他登录方式 这些 PAM 配置不仅影响 SSH还会影响本地终端登录tty、su命令、图形界面登录如 GDM等所有通过 PAM 进行认证的入口。这是一个全局性的安全提升。5.3 边界场景与注意事项服务账户 对于像nginx、mysql、redis这类服务账户它们通常使用密钥或套接字认证不涉及密码登录。失败锁定策略对它们一般没有影响。但如果你为这些账户设置了密码并用于某些管理操作则需要留意。sudo 操作sudo命令本身也会进行认证验证你的用户密码。连续输错sudo密码是否会被锁定这取决于/etc/pam.d/sudo这个 PAM 配置文件是否也包含了pam_faillock模块。通常为了管理便利sudo的失败可能不计入登录失败锁定或者有独立的策略。你需要根据实际安全要求来配置。锁定后的恢复手动解锁 使用faillock --user username --reset。自动解锁 等待unlock_time设置的时间过后账户会自动解锁。紧急恢复 如果唯一的管理员账户被锁且无法通过控制台你可能需要重启进入单用户模式或恢复模式来修改 PAM 配置或重置密码。配置备份与版本管理 将/etc/pam.d/下的关键文件和/etc/security/pwquality.conf、/etc/security/faillock.conf进行备份。如果使用自动化工具如 Ansible, Puppet将这些配置纳入版本管理以便在新建服务器时快速、一致地部署。6. 高级策略与自动化监控基础配置完成后可以考虑一些增强措施让安全防护更智能、更省心。6.1 设置密码过期与强制更换强密码也不是一劳永逸的。可以通过/etc/login.defs文件设置密码的最大有效期强制用户定期更换。sudo vim /etc/login.defs找到并修改以下参数PASS_MAX_DAYS 90 # 密码最多使用90天 PASS_MIN_DAYS 7 # 密码修改后至少7天内不能再次修改 PASS_WARN_AGE 14 # 在密码过期前14天开始警告用户这些设置对新创建的用户立即生效。对于已存在的用户需要使用chage命令来修改# 查看testuser_complex的密码策略 sudo chage -l testuser_complex # 修改其密码最大有效期 sudo chage -M 90 testuser_complex6.2 与系统日志和监控告警集成安全配置的最后一环是“可观测性”。你需要知道什么时候有人触发了你的防线。集中查看认证日志grep和journalctl是你的好朋友。可以定期运行一些命令来检查异常。# 查看过去一小时所有的失败登录尝试 sudo journalctl --since -1h _COMMsshd | grep -i fail # 查看所有被锁定的账户事件 sudo journalctl -g pam_faillock.*locked配置日志告警 使用像logwatch、fail2ban虽然fail2ban本身是主动封锁IP的但它也依赖日志分析这样的工具或者将系统日志 (/var/log/auth.log) 发送到中央日志服务器如 ELK Stack, Graylog并设置告警规则。例如可以设置“同一用户在一分钟内失败登录超过3次”就发送邮件或Slack通知给管理员。6.3 使用Fail2ban进行IP层面的主动防御pam_faillock锁定的是用户账户而Fail2ban则可以更进一步它扫描日志文件如/var/log/auth.log当发现某个IP地址在短时间内有多次失败登录尝试时会自动修改防火墙规则如 iptables 或 ufw临时禁止该IP地址访问特定端口如SSH的22端口。这是一种在应用层PAM和网络层防火墙之间的协同防御。即使攻击者使用不同的用户名进行尝试只要来自同一个IPFail2ban也能将其屏蔽。安装和配置Fail2ban是另一个话题但其核心思想是PAM失败锁定 Fail2ban IP封锁构成了从用户维度到IP维度的双重立体防护能极大地增加攻击者的成本和难度。7. 常见问题与排查技巧实录在实际配置和运维中你肯定会遇到各种“坑”。下面是我总结的一些典型问题及其解决方法。7.1 配置后所有用户包括自己无法登录症状 修改/etc/pam.d/common-auth后退出当前会话发现无法再登录即使密码正确。原因 几乎可以肯定是在 PAM 配置文件中出现了语法错误或逻辑错误导致认证栈被破坏。例如模块顺序错乱、使用了错误的控制标志required,sufficient等。解决方案紧急利用云服务器控制台VNC/串口 这是最可靠的恢复方式。通过云服务商提供的网页控制台登录你拥有的是物理终端权限不受PAM配置影响。进入单用户/恢复模式 如果服务器有物理访问权限在启动时进入GRUB菜单选择恢复模式Recovery Mode通常会挂载根文件系统并提供一个root shell。从备份恢复 如果你遵循了建议修改前备份了原文件例如sudo cp /etc/pam.d/common-auth /etc/pam.d/common-auth.backup在恢复模式的root shell中将其覆盖回去即可。逐行检查 在恢复环境中仔细检查你添加或修改的每一行。特别注意pam_faillock.so那几行的顺序和参数。一个常见的错误是把authsucc模块放错了位置。预防永远在测试环境或虚拟机上先验证配置。修改生产环境的PAM前先打开另一个活跃的SSH会话不要退出在新会话中测试su到另一个用户或使用ssh localhost来验证认证是否正常。确认无误后再关闭那个“保命”的会话。7.2 密码策略对某些用户不生效症状 为新用户设置的密码策略对已有的老用户似乎不起作用。原因 密码策略在用户修改密码时生效。老用户的密码是在旧策略下设置的只要不修改系统不会强制要求其符合新策略。解决方案使用chage命令强制用户在下次登录时修改密码sudo chage -d 0 username这样用户下次登录时系统会强制要求其设置新密码此时新密码就必须符合当前的复杂度策略了。编写脚本批量处理现有用户要求他们定期更新密码。7.3 失败锁定对sudo无效或行为异常症状 用户登录失败会被锁定但连续输错sudo密码却不会。原因/etc/pam.d/sudo配置文件默认可能没有包含pam_faillock模块。sudo的认证是独立的PAM栈。解决方案 根据你的安全策略决定是否需要统一。如果需要让sudo失败也计入锁定可以参照common-auth的配置方式在/etc/pam.d/sudo文件中相应位置添加pam_faillock模块。但务必谨慎因为锁定了sudo权限可能导致用户无法进行必要的管理操作。7.4 系统重启后失败计数被清零症状 配置了pam_faillock用户被锁定。但服务器重启后该用户又可以登录了。原因pam_faillock默认将失败计数存储在/var/run/faillock/目录下。这个目录是tmpfs内存文件系统重启后数据自然丢失。解决方案 如果你需要持久化的失败计数即重启后锁定状态依然保持需要修改配置将计数存储到磁盘上。创建一个持久化目录例如/var/lib/faillocksudo mkdir -p /var/lib/faillock在/etc/security/faillock.conf中或 PAM 模块参数中指定dir选项dir /var/lib/faillock或者在/etc/pam.d/common-auth的pam_faillock.so行中添加dir/var/lib/faillock参数。7.5 如何为不同用户组设置不同的密码策略这是一个更进阶的需求。PAM 本身可以通过pam_succeed_if等模块实现条件判断但配置较为复杂。一个更清晰的方法是结合使用libpam-pwquality的另一个特性通过/etc/security/pwquality.conf.d/目录进行覆盖配置。你可以为特定用户或组创建单独的配置文件。例如为admin组设置更严格的策略创建文件/etc/security/pwquality.conf.d/admin.conf。在其中写入更严格的配置如minlen16minclass4。然而标准的pam_pwquality模块并不直接支持按用户/组读取不同配置文件。要实现这一点通常需要更复杂的 PAM 栈编排或者考虑使用像libpam-sss配合外部身份管理系统如 LDAP来实现中心化的、细粒度的密码策略。对于大多数单机或小规模场景统一的严格策略通常是更简单有效的选择。