1. 项目概述:为什么需要账户锁定策略?
在Linux服务器,特别是Ubuntu这类广泛用于生产环境的系统中,账户安全是运维的第一道防线。想象一下,你管理的服务器暴露在公网,总有不怀好意的脚本小子尝试用“admin”、“root”、“123456”这类弱密码进行暴力破解。如果放任不管,他们可以无限次尝试,直到撞库成功,你的数据和服务就危在旦夕了。账户锁定策略,就是在多次连续输错密码后,自动将账户临时或永久锁定的安全机制。这就像你家门锁,连续输错几次密码,锁芯就会暂时冻结,防止有人拿万能钥匙一直试。
在Ubuntu中,这个功能并非系统默认强力开启,需要我们手动配置。它主要依赖于一个名为PAM(Pluggable Authentication Modules,可插拔认证模块)的底层框架。PAM是Linux身份验证的“中央处理器”,所有登录行为(SSH、本地控制台、图形界面登录)都要经过它。通过配置PAM,我们可以精细地控制认证策略。本次要实现的,就是利用PAM的pam_tally2模块(在新系统中也可能是pam_faillock),来构建一个可靠的账户登录失败防御体系。对于任何需要将Ubuntu服务器对外提供服务的管理员来说,这都是一项必须掌握的基础安全加固技能。
2. 核心组件与原理深度解析
2.1 PAM框架:安全策略的基石
要玩转账户锁定,必须先理解PAM。你可以把PAM想象成一个高度模块化的安检系统。当用户尝试登录时(比如输入密码),这个请求会先递交给PAM。PAM本身不判断密码对错,它只负责协调流程:按照预设的“安检程序”(即PAM配置文件),依次调用各个专业的“安检模块”(如pam_unix.so验证密码,pam_tally2.so计数失败次数)。
PAM的配置文件通常位于/etc/pam.d/目录下,里面针对不同的服务有独立的配置,例如common-auth(通用认证)、login(本地终端登录)、sshd(SSH远程登录)等。我们要修改的,正是这些文件。模块的调用有四种控制标志:
required:模块必须成功。即使失败,也会等所有模块执行完才返回失败。requisite:模块必须成功。一旦失败,立即返回失败,后续模块不再执行。sufficient:模块成功则立即通过认证,忽略后续的required模块。optional:模块成功与否不影响整体认证结果。
对于账户锁定,我们通常使用required标志,确保失败计数和锁定检查是强制性的环节。
2.2 pam_tally2 模块的工作机制
pam_tally2模块是实现计数和锁定的核心。它主要有两个功能:
- 计数:在认证失败时,对相应用户的失败次数进行累加。
- 检查:在认证开始时,检查该用户的失败次数是否已超过阈值,如果超过,则直接拒绝本次登录尝试。
它的工作依赖于一个“账本”文件,默认是/var/log/faillog或/var/log/tallylog,里面以二进制格式记录了每个用户的失败次数和最近失败时间。当失败次数达到我们设定的上限(例如5次),模块就会触发锁定。锁定有两种模式:
- 自动解锁:锁定一段时间(如600秒),时间一到,计数器清零或允许再次尝试。
- 手动解锁:锁定后必须由管理员使用
pam_tally2命令手动重置计数器。
这里有一个关键细节:pam_tally2模块在配置时需要被调用两次。第一次在auth阶段(检查账户密码之前),用于“检查”是否已锁定;第二次在account阶段(或auth阶段失败后),用于“计数”失败次数。顺序弄反了就会失效。
注意:在 Ubuntu 22.04 及更新版本中,官方更推荐使用
pam_faillock模块,它功能更现代,语法略有不同。但pam_tally2在旧版本和许多其他发行版中依然广泛使用,原理相通。下文会以pam_tally2为例详解,并在最后补充pam_faillock的配置差异。
2.3 策略设计考量:平衡安全与便利
在配置前,我们需要想清楚策略,避免把自己锁在外面。
- 失败次数阈值:设为多少?3次太敏感,容易误锁;10次又太宽松。对于服务器,5-6次是常见选择。
- 锁定时间:是永久锁定直到管理员干预,还是自动解锁?生产环境通常建议自动解锁(如10-30分钟),既阻止了暴力破解,又避免了因管理员遗忘而导致的服务账户永久不可用。但针对特别敏感的系统或特定用户(如root),可以考虑永久锁定并邮件告警。
- 作用范围:是锁定所有用户,还是排除某些服务账户?通常,系统内置的非登录账户(如
www-data,mysql)不需要此策略,但所有可登录的普通用户和root都应覆盖。 - 重置时机:成功登录后,失败计数器是否清零?是的,这是
pam_tally2的默认行为,这很合理。
3. 详细配置步骤与实操
下面我们以配置SSH服务和本地登录(login)为例,演示完整的配置过程。假设我们的策略是:连续失败5次后,锁定账户600秒(10分钟)。
3.1 环境准备与备份
在修改任何PAM配置文件之前,备份是铁律。打开终端,执行:
sudo cp /etc/pam.d/common-auth /etc/pam.d/common-auth.backup sudo cp /etc/pam.d/sshd /etc/pam.d/sshd.backup sudo cp /etc/pam.d/login /etc/pam.d/login.backup这样,万一配置出错导致所有用户无法登录,我们还可以通过恢复模式或单用户模式回滚备份文件。
3.2 配置 SSH 登录锁定策略
SSH是远程攻击的主要入口,我们先加固它。
编辑SSH服务的PAM配置:
sudo nano /etc/pam.d/sshd在文件的开头部分(通常在
@include common-auth这行之前),添加以下两行:# 检查失败次数,超过5次则拒绝访问 auth required pam_tally2.so deny=5 unlock_time=600 onerr=succeed file=/var/log/tallylog # 统计登录失败次数(仅在认证失败时计数) account required pam_tally2.so参数解析:
deny=5:失败次数阈值。unlock_time=600:锁定时间(秒),600秒=10分钟。设置为0表示永久锁定,直到手动重置。onerr=succeed:即使模块内部出错(如无法写入日志文件),也让认证流程继续。这是一个安全兜底,避免因模块自身问题导致所有人都无法登录。生产环境建议加上。file=/var/log/tallylog:指定记录失败次数的账本文件路径。
配置顺序至关重要:
auth阶段的pam_tally2(带参数)必须在其他认证模块(如pam_unix.so)之前执行,用于先行检查是否已锁定。account阶段的pam_tally2放在后面,负责计数。保存并退出编辑器(在nano中按
Ctrl+X,然后按Y,最后回车)。
3.3 配置本地控制台登录锁定策略
对于服务器本地的文本或图形化登录,需要修改/etc/pam.d/login文件(图形化登录如GDM可能涉及其他文件,但原理类似)。
- 编辑文件:
sudo nano /etc/pam.d/login - 采用与
sshd相同的配置,在文件开头合适位置添加同样的两行。注意,有些系统在login文件中已经存在一些pam_tally2行,请先检查,避免重复。
3.4 配置通用认证策略(可选但推荐)
为了确保策略覆盖所有通过PAM认证的服务(如sudo、su等),最好也修改/etc/pam.d/common-auth。但这里需要更小心,因为影响面广。
- 编辑文件:
sudo nano /etc/pam.d/common-auth - 找到以
auth [success=1 default=ignore]开头的那一行(这是调用pam_unix.so的模块行)。在这行之前,插入我们的检查行:auth required pam_tally2.so deny=5 unlock_time=600 onerr=succeed file=/var/log/tallylog - 接着,我们需要在
account部分添加计数行。找到account相关的段落(通常以account [default=bad success=ok user_unknown=ignore] pam_unix.so结尾),在这行之后,添加:account required pam_tally2.so
3.5 手动管理锁定账户
配置完成后,我们需要掌握管理命令。
- 查看所有用户失败次数:
sudo pam_tally2 - 查看指定用户失败次数:
sudo pam_tally2 --user username - 手动解锁(重置)某个用户:
这个命令会将指定用户的失败计数清零,立即解除锁定。sudo pam_tally2 --user username --reset - 重置所有用户的失败计数(谨慎使用):
sudo pam_tally2 --reset
3.6 针对 Ubuntu 22.04+ 的 pam_faillock 配置
在新版Ubuntu中,如果发现pam_tally2模块不存在或无效,可以使用pam_faillock。
- 编辑
/etc/pam.d/common-auth,在文件顶部添加:auth required pam_faillock.so preauth silent deny=5 unlock_time=600 auth required pam_faillock.so authfail deny=5 unlock_time=600preauth在认证前检查,authfail在认证失败后计数。 - 编辑
/etc/pam.d/common-account,在文件末尾添加:account required pam_faillock.so - 管理命令也变了:
- 查看状态:
sudo faillock --user username - 重置用户:
sudo faillock --user username --reset
- 查看状态:
4. 配置验证与测试
配置完不测试,等于没做。务必在另一个活跃的SSH会话窗口进行测试,防止把自己锁在外面导致失联。
- 新建一个测试用户:
设置一个简单的密码。sudo adduser testlock - 在另一个终端或SSH窗口,用错误密码尝试登录:
连续输入错误密码5次。ssh testlock@你的服务器IP - 观察现象:第5次失败后,你应该会看到类似
Account locked due to X failed logins的提示。第6次尝试时,可能在输入密码前就直接被拒绝。 - 验证锁定:在服务器原会话中,运行
sudo pam_tally2 --user testlock,会看到失败次数为5,且账户被锁定。 - 测试自动解锁:等待10分钟(或你设置的
unlock_time),再次尝试用正确密码登录,应该可以成功。成功后再次查看计数,应该被重置为0。 - 测试手动解锁:再次锁定测试账户后,使用
sudo pam_tally2 --user testlock --reset命令重置,然后立即尝试登录,应该成功。
5. 常见问题、故障排查与进阶技巧
5.1 常见问题速查表
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 配置后所有用户(包括root)都无法登录 | 1. PAM配置语法错误。 2. onerr=succeed参数未加,且日志文件不可写。3. 模块顺序错误,导致检查逻辑死循环。 | 1. 通过备份文件恢复,仔细检查语法。 2. 确保 /var/log/tallylog文件存在且PAM进程有写权限(通常属主root,权限600)。3. 确保 auth阶段的检查行在pam_unix.so等认证模块之前。 |
| 失败次数不累计,或成功登录后不清零 | 1.account阶段的pam_tally2行缺失或位置错误。2. 不同服务(sshd, login)使用了不同的日志文件,导致计数不统一。 | 1. 确认account required pam_tally2.so这行已正确添加到配置中。2. 在所有PAM配置文件中,为 pam_tally2指定相同的file=路径。 |
pam_tally2命令未找到或执行报错 | 1. 系统未安装该模块。 2. 在新版系统中被 pam_faillock取代。 | 1. 安装libpam-modules包:sudo apt install libpam-modules。2. 切换到使用 pam_faillock模块和faillock命令。 |
| 锁定策略对某个特定用户不生效 | 该用户可能被配置了nologinshell,或者其登录方式绕过了PAM(如密钥认证)。 | SSH密钥认证确实不触发密码失败计数。确保测试时使用的是密码认证。检查用户shell是否为/sbin/nologin或/bin/false。 |
5.2 故障排查心法
如果遇到问题,按以下顺序排查:
- 检查PAM调试日志:在
/etc/pam.d/sshd的模块行中添加debug参数,如auth required pam_tally2.so deny=5 unlock_time=600 debug。然后通过sudo tail -f /var/log/auth.log观察SSH登录时的详细PAM流程信息。这是最强大的排错手段。 - 检查系统日志:
/var/log/auth.log和/var/log/syslog是宝藏,任何认证相关的错误都会记录在这里。使用grep pam_tally2 /var/log/auth.log或grep faillock来过滤关键信息。 - 验证配置文件语法:使用
pam-auth-update命令可以交互式地管理一些通用PAM配置,但对我们手动添加的行无效。更直接的是用pamtester工具模拟认证:sudo apt install pamtester,然后pamtester sshd username authenticate来测试。
5.3 进阶技巧与最佳实践
- 为root账户设置更严格的策略:可以在配置中针对root用户单独设置更低的失败阈值(如3次)和更长的锁定时间,甚至永久锁定,然后通过其他方式(如物理控制台、预先配置的授权密钥)进行紧急解锁。
- 结合Fail2ban实现IP封锁:
pam_tally2锁定的是用户账户。攻击者可以换一个用户名继续尝试。Fail2ban可以监控认证日志,发现来自同一IP的多次失败后,直接使用iptables封锁该IP地址一段时间,实现用户+IP的双重防护。 - 设置报警通知:编写一个简单的Shell脚本,定期检查
/var/log/tallylog或使用pam_tally2命令,如果发现root用户或关键管理用户被锁定,立即发送邮件或短信告警给管理员。 - 将配置纳入版本管理:将
/etc/pam.d/目录下的关键配置文件纳入Git等版本控制系统。这样,任何更改都有记录,回滚也极其方便。 - 注意Docker容器环境:在容器内,PAM通常不被使用或配置不同。容器安全应更多依赖于镜像安全、网络隔离和宿主机的安全策略,而非容器内的账户锁定。
账户锁定策略是一个“沉默的卫士”,它不会每天刷存在感,但能在关键时刻挡住绝大部分自动化密码爆破攻击。花半小时配置并测试好它,是每个Linux系统管理员对自己和业务负责的基本体现。记住,安全不是一个功能,而是一个持续的过程,从这样一个个扎实的基础配置开始。