首页 / 资讯中心 / 文章详情

Linux账户锁定机制与防暴力破解:从PAM配置到应急解锁

Linux账户锁定机制与防暴力破解:从PAM配置到应急解锁 ★ FEATURED ARTICLE
上周五下午我处理完一批SSH暴力破解告警晚上就收到一条求助截图引用的账户已锁定且可能无法登录发消息的人用着统信UOS桌面环境root账户被锁住了问我有没有办法解开。这两个场景看着一个在服务器端、一个在桌面端但底层其实是同一件事账户锁定与防暴力破解机制。这篇就围绕这个话题展开讲清楚锁定机制怎么配置、如何验证它真的生效、被锁死之后怎么救回来以及远程桌面场景下那种账户已锁定的提示到底是怎么回事。适合运维、安全测试、系统管理员看也适合遇到账户被锁问题的普通用户——只要搞明白PAM和账户锁定策略是怎么交互的大多数锁死问题都能自己解决。1. 暴力破解远比想象中密集账户锁定机制的位置和边界1.1 攻击者为什么死盯着你的登录入口你只要把一个带SSH的Linux主机放到公网即便只是个2核4G的小ECS日志里也会很快出现扫描记录。常见的样子是这样Mar 9 02:33:15 node1 sshd[21208]: Failed password for invalid user admin from 61.xx.xx.xx port 51003 Mar 9 02:33:16 node1 sshd[21210]: Failed password for invalid user admin from 61.xx.xx.xx port 51003 Mar 9 02:33:17 node1 sshd[21211]: Failed password for invalid user root from 61.xx.xx.xx port 51003这是典型的字典爆破攻击者手里有一份用户名高频密码的字典对着一批IP批量尝试。现代爆破工具还能做分布式打点同一个IP最多试两三次就换源防止被单IP封禁策略拦住。远程桌面也是一样的逻辑只要RDP端口暴露在外网账户锁定策略几乎是唯一能拦住反复猜密码的系统层机制。这里要先说清楚一个基本原则暴力破解的核心成本是尝试次数 × 每次尝试的时间账户锁定的作用就是把尝试次数压住——连续输错几次账户直接或多长时间内不可用攻击者再猜下去也没有收益。它不是一个能根治弱密码的方案但它是止损阀配合强密码、密钥登录、访问来源限制才能真正把暴力破解挡在门外。1.2 账户锁定在防御链条中的位置我平时做安全基线时会把账户锁定归到认证策略这一层。它要解决的问题很明确在密码已经被猜到的边缘把登录入口暂时封住。但它也有三个明显的边界通用密码喷洒攻击里攻击者通常用同一个密码去试大量账号单账号失败次数不多锁定机制很难触发攻击者控制了大量源IP时即使每个账户锁定他们仍然可以换账户继续试如果攻击目标本身就是管理员账户锁定的效果取决于你设不设even_deny_root这类参数。所以账户锁定要放在纵深防御里看网络层有fail2ban封IP系统层有PAM锁定账户应用层再配合双因子。每一层都挡一部分哪一层被绕过都不至于直接失守。2. 机制主体是PAMfaillock与tally2等方案的配置拆解2.1 锁定的实现层级为什么绕不开PAM在Linux系统里用户认证不是SSH或图形登录直接判断的它统一交给PAM可插拔认证模块处理。你输入密码后SSH、login、xrdp都会调用PAM的认证栈PAM按/etc/pam.d/下配置文件的顺序逐个执行模块。账户锁定就是在这一层插入一个计数裁决的动作。常见实现有几种老牌的是pam_tally2新系统推荐的是pam_faillock再往上还能叠fail2ban这类应用层封禁。名字有点接近但关注点不同方案拦截维度数据存储适用系统备注pam_faillock账户级/run/faillockRHEL 7、Debian系当前主流推荐pam_tally2账户级/var/log/tallylogCentOS 6/7新版本逐渐弃用fail2ban来源IP级数据库/文件所有独立于PAM针对IPWindows账户锁定账户级SAM/ADWindows/RDP组策略设置需要注意PAM锁定管的是账户fail2ban管的是来源IP。账户锁定能挡住单账户的反复尝试但挡不住大量不同IP的低频攻击IP封禁能挡住单IP的密集请求但挡不住密码喷洒。所以两者不是二选一而是叠加使用。2.2 RHEL/CentOS系的pam_faillock配置在RHEL 7/8/9、CentOS系上修改的是/etc/pam.d/system-auth和/etc/pam.d/password-auth。核心配置片段如下auth required pam_faillock.so preauth silent audit deny4 unlock_time900 even_deny_root auth sufficient pam_unix.so nullok try_first_pass auth [defaultdie] pam_faillock.so authfail audit deny4 unlock_time900 even_deny_root account required pam_faillock.so解释一下各行的职责第一行preauth在用户还没输入密码前先检查当前账户是否已被锁定如果锁了就拒绝认证第二行pam_unix.so是正常的密码校验第三行authfail在密码验证失败后追加记录并判断是否达到deny次数第四行account在账户阶段再次检查锁定状态防止绕过认证阶段直接进入。参数里deny4表示连续4次失败触发锁定unlock_time900表示锁定900秒even_deny_root表示root账户同样参与锁定。如果你的安全基线要求root也不可例外就必须保留这个参数如果你担心根账户被锁死导致无法应急就去掉它。在RHEL 8/9上还有个更干净的做法使用authselect配置集。先查看当前配置authselect current然后启用带faillock的profileauthselect select sssd with-faillock启用后系统会自动把PAM配置生成到/etc/pam.d/system-auth。如果要微调参数例如把失败次数改成3次、锁定时间改成600秒就直接在生成后的配置里动文件或通过authselect enable-feature配合自定义profile来做。我不建议完全手写覆盖因为authselect再次执行时会把你的手写改动冲掉出问题都不知道怎么排查。2.3 Debian/Ubuntu/统信UOS系common-auth的差异Debian系的PAM策略文件分散在/etc/pam.d/common-auth、common-account、common-password里统信UOS基于Debian架构所以配置逻辑一致。要启用pam_faillock在/etc/pam.d/common-auth顶部加两段auth required pam_faillock.so preauth auth [success1 defaultignore] pam_unix.so nullok auth [defaultdie] pam_faillock.so authfail然后在/etc/pam.d/common-account顶部加一行account required pam_faillock.so顺序很重要pam_unix.so行里的[success1 defaultignore]是个跳转逻辑——密码验证成功就跳到下一行失败就落到pam_faillock.so authfail去记账。如果顺序写反计数可能不准锁不锁得看运气。需要说明的是不同版本的Debian/Ubuntu在common-auth里默认就有pam_unix.so所以实际添加时要把原有那行替换成上面带跳转状态的写法而不是简单追加。UOS系统用户可能还会遇到系统自带的深度定制登录界面某些场景下计数文件和日志路径略有差异但PAM层面逻辑是一致的。2.4 deny、unlock_time、even_deny_root参数取舍背后的事情这几个参数值得单独拿出来讲因为配置的时候很容易想当然。deny设置太小比如1或2对正常用户非常不友好输错一次手滑就锁半小时设置太大又失去意义比如10次暴力破解工具跑起来很快就能到10次然后换一个账户继续。我的经验是公网SSH入口设3到5次内网办公系统的图形登录可以放宽到5到8次把误伤和防护平衡起来。unlock_time是锁定时间单位秒。900秒15分钟是很多人用的默认值不算长也不算短。如果攻击者是自动化脚本15分钟后他大概率还挂着继续试如果是真实用户手滑输错15分钟等得起。但如果你有敏感业务系统比如堡垒机、数据库跳板机可以把锁定时间拉到1800秒甚至3600秒。even_deny_root是个容易让管理员翻车的参数。设了它root也参与锁定但攻击者难以爆破root的同时你本人也可能因为输错密码被锁在门外。我的建议是在有带外管理通道、有sudo用户能救急的环境里可以开启如果是单机没有其他入口root参与锁定前必须先想好解锁路径否则别加这个参数。3. 实测锁定触发到解锁的全流程3.1 测试环境准备别拿生产机开玩笑账户锁定机制测试最忌讳直接在生产环境改PAM然后试错一旦配置错了SSH连不上、控制台进不去只能干瞪眼。我的做法是开一台虚拟机或LXC容器系统选型和线上一致改完配置再测试。如果是测试RHEL就准备RHEL环境测试UOS就装一个UOS虚拟机。测试前确认三件事当前系统有至少一个可用的sudo用户密码你知道有一条不依赖密码认证的登录路径比如虚拟机的控制台、带外管理、或者密钥登录你计划修改的PAM文件已经备份。cp /etc/pam.d/system-auth /etc/pam.d/system-auth.bak.$(date %F)有了这个备份哪怕改坏了也能在单用户模式里cp回去。3.2 制造错误登录脚本与手动的两种方式配置完成后找一个测试专用账户不要用生产管理员账号。先在终端里手动输错密码最直观login: testuser Password: Login incorrect连续输错5次之后第6次再输对密码也会被拒。但手动一场一场太慢我用脚本做SSH维度的测试更典型。下面这个例子用sshpass模拟连续错误密码登录本机SSHfor i in $(seq 1 8); do sshpass -p wrongpass_$i ssh -o StrictHostKeyCheckingno \ -o ConnectTimeout3 testuser127.0.0.1 21 | grep -E Permission denied|locked|denied sleep 1 done注意两点第一这个脚本只应该在测试环境跑不要把sshpass装在生产机器上第二SSH登录失败后会有一点认证延迟脚本里的sleep 1是为了让日志和分析工具节奏更接近真实攻击场景。如果测试的是本地登录可以更简单直接用su - testuser连续输错。3.3 从日志和faillock命令确认锁定生效测试完怎么确定锁定真的生效两条路径看日志、看faillock状态。RHEL/CentOS系看/var/log/secureDebian/UOS看/var/log/auth.log。典型记录长这样Mar 9 14:22:04 testnode sshd[2240]: Failed password for testuser from 127.0.0.1 port 51234 Mar 9 14:22:05 testnode sshd[2251]: Failed password for testuser from 127.0.0.1 port 51235 Mar 9 14:22:06 testnode sshd[2262]: Failed password for testuser from 127.0.0.1 port 51236如果达到锁定阈值auth.log里会出现类似pam_faillock(testuser): User has been locked due to X failed logins的记录。再看模块的计数faillock --user testuser正常输出会列出用户、触发时间、来源、锁定状态。croot用户同样可以查faillock --user root这里有个容易踩的坑pam_faillock的计数文件保存在/run/faillock下而/run是tmpfs系统重启后计数会清零。也就是说你在测试中发现账户被锁定重启一下就又能登录了。这既是一个意外解锁手段也是个安全隐患——攻击者自然也可以尝试重启目标系统来绕过锁定所以生产环境最好同时有fail2ban等其他机制兜底。3.4 管理员解锁与回归验证锁定了之后管理员解锁的命令很简单faillock --user testuser --reset执行后再用正确密码登录应该立刻成功。整个锁定-解锁-再登录的闭环就完整了。回归验证时我会顺手检查几件事正确的密码在锁定期间是否确实被拒解锁后计数是否清零重启后计数是否丢失deny和unlock_time参数修改后行为是否符合预期。每改一次参数就重跑一遍脚本形成一份改了什么、验证了什么、结果如何的记录这个习惯对审计和排障都非常有用。4. root账户被锁后的应急通道统信UOS与RHEL实战解锁4.1 root锁定到底是怎么触发的很多人遇到统信UOS系统root账户锁定第一反应是懵的。我复盘过几个类似案例触发路径大同小异要么是某些第三方脚本或软件安装时自动往PAM配置里加了even_deny_root要么是管理员在配置防暴力破解策略时把root计入锁定之后某次手滑输错几次密码root就被锁住了。root锁定的麻烦在于系统其他用户可能没有sudo权限或者干脆其他用户也没启用这时候你连用另一个用户登录再去解锁的机会都没有。4.2 有sudo用户时的现场解锁如果系统里还有一个可登录的sudo用户事情简单得多。登录那个用户后执行sudo faillock --user root --reset如果之前设过even_deny_rootroot账户的计数被清零后就能重新登录了。这里补充一点faillock --reset只清空计数不修改密码密码不需要重新设置密码。如果没有faillock命令也可以直接删计数文件sudo rm -f /run/faillock/root不过直接删文件这种操作不推荐在生产环境乱试不同发行版的文件路径有差异faillock --reset是更规范的做法。4.3 没有可用sudo用户时单用户模式与Live环境最麻烦的情况是全系统没有任何普通用户能登录root也被锁。这时候只能走恢复通道。以RHEL/CentOS为例重启机器在GRUB菜单按e编辑启动项找到linux开头的那一行在末尾追加rd.break然后按CtrlX启动。进入紧急shell后依次执行mount -o remount,rw /sysroot chroot /sysroot faillock --user root --reset如果chroot进去后发现没有faillock命令也可以直接用rm -f /run/faillock/root——注意chroot环境里的/run其实来自原系统挂载但如果你是在Live环境直接挂载了原系统盘情况又不一样需要先确认路径。最保险的做法是在chroot里执行rm -f /run/faillock/root passwd root重置密码能覆盖因锁定无法登录的状态即使计数还在你也有了新的密码而且如果unlock_time已经到期或计数被passwd流程重置即可登录。统信UOS的处理思路类似。UOS桌面版基于Debian开机时进恢复模式更容易在GRUB启动菜单选择Advanced选项进入recovery mode然后选择root Drop to root shell prompt。进去后先执行mount -o rw,remount /因为恢复模式下根分区通常是只读挂载不重新挂载成可写后面的修改都写不进去。然后同样执行faillock --user root --reset或删除计数文件。UOS的恢复模式如果进不去就做启动U盘用Live系统挂载根分区处理。4.4 避免root锁定的长效习惯经历过一次root锁死之后我给自己定了几条规矩只有通过sudo执行管理员操作默认不直接以root做日常登录设置PAM锁定策略时root不参与锁定的场景保留一个专门的管理员通道如带外控制台或跳板机白名单路径每次修改PAM配置前先备份并检查root的faillock计数是否异常对桌面用户锁定期限不要设置得太长900秒内比较合适避免用户等着急又不敢乱动。这些习惯说白了就是不要把自己这个管理员锁在外面。很多安全策略不是不好而是没有留足逃生通道最后反而成为运维事故的源头。5. 远程桌面报账户已锁定这类提示背后的策略与修正5.1 这条提示从哪来引用的账户已锁定且可能无法登录是远程桌面连接失败时常见的Windows提示英文原文是the referenced account is currently locked out and may not be logged on to。触发前提是目标Windows机器配置了账户锁定策略连续失败密码达到阈值后该账户在指定时间内被禁止登录。这个策略在本地安全策略里配置。打开secpol.msc找到安全设置 - 账户策略 - 账户锁定策略有三个值策略项推荐值说明账户锁定阈值5次无效登录设为0表示从不锁定账户锁定时间30分钟锁定持续时长重置账户锁定计数器时间30分钟计数清空周期设置后一旦远程桌面用户连续输错5次密码再连接就会直接报引用的账户已锁定且可能无法登录。这是Windows侧防止RDP暴力破解的主要手段之一。5.2 Windows管理员怎么解锁如果是域环境域账号通常由域控统一管理管理员在域控上用PowerShell解锁Unlock-ADAccount -Identity zhangsan如果只是本机账户可以打开lusrmgr.msc本地用户和组找到对应用户在属性里取消勾选账户已锁定。本地账户也可以用命令行查看账户状态net user zhangsan输出里如果出现账户已锁定就说明问题出在锁定策略上。解锁前先确认不是密码错、不是账户禁用避免解了锁仍然登不进去。5.3 Linux远程桌面的类似场景xrdp与PAM的联动在Linux上装xrdp提供远程桌面时底层登录还是走PAM因此前面配置的pam_faillock对远程桌面同样生效。也就是说如果有人对着你的RDP地址反复试密码账户也会被锁。这就产生了一个常见的误伤场景管理员自己在xrdp上连续输错几次密码结果锁的是系统账号而不再是Windows那种独立的RDP锁定状态。处理方式和第4章一致只要有sudo用户登录sudo faillock --user 用户名 --reset即可解锁没有的话控制台登录或单用户模式处理。这里要特别提醒一个细节在配置xrdp pam_faillock的主机上别把unlock_time设得太长。桌面场景下用户输入错误的概率比SSH高得多一旦锁30分钟普通用户会直接拨打你的手机号。我的习惯是xrdp的锁定阈值可以比SSH略微放宽比如SSH设5次桌面登录设8次毕竟桌面端还有图形验证码、登录频率限制等因素兜底。如果想让Windows的引用的账户已锁定且可能无法登录提示在远程桌面环境里更少出现终极方案是把接入入口收敛到跳板机用户在跳板机上完成一次认证后再转发到目标主机。这样即便密码被爆破目标机的账户锁定策略也不会被频繁触发。6. 把账户锁定机制测试做成日常运维动作6.1 安全基线上的验收测试清单配置过、测试过、解锁过这套机制就算真正跑通了。但我不建议把测试当一次性动作而应该固定成每个季度或每次安全基线变更后的验收项。我给自己的验收清单包含这几条修改PAM配置前已备份当前生效配置能被pam_faillock规则覆盖用测试账户连续失败deny次确认账户被锁定日志有记录锁定期间使用正确密码登录必须被拒faillock --user 用户 --reset后可以立即登录root账户是否参与锁定参与的话解锁路径明确重启后计数清空这一特性已了解不复用锁定作为唯一防线。每一条都对应一个具体操作而不是看起来没报错这样才能在策略变更后尽早发现问题。6.2 一个简单的失败登录检测脚本如果机器数量多人工去翻日志不现实。我用journald做一个轻量脚本统计最近5分钟的SSH失败次数超过阈值就告警#!/bin/bash # 统计最近5分钟内SSH登录失败次数超过阈值告警 count$(journalctl --since 5 minutes ago --no-pager 2/dev/null | grep -c Failed password) threshold20 if [ $count -gt $threshold ]; then echo SSH失败次数异常: ${count} 次 | mail -s SSH暴力破解告警 opsexample.com fi脚本放进cron每分钟跑一次也没问题journalctl的--since时间窗口就是告警窗口。RHEL/CentOS上如果日志也在journald里同样的写法可用如果日志习惯写到传统文件就改成统计/var/log/secure或/var/log/auth.log里的Failed password行数。有fail2ban的环境还可以顺手查一下当前封禁列表fail2ban-client status sshd把封禁数量和失败次数放在同一个告警里判断会更准。某段时间封禁数量暴涨基本可以认定有人在扫你的端口即使PAM没触发锁定也说明入口暴露得比较厉害。6.3 业务连续性的兜底设计最后想聊的是锁不死自己这个目标。账户锁定策略上线后最尴尬的不是攻击者进不来而是管理员自己也进不去。我见过一家公司把deny2、unlock_time1800同时加到所有Linux服务器上结果第二天就有人因为输错两次密码被锁15分钟运维值班电话直接被打爆。所以做任何锁定策略之前先回答三个问题有没有一条不依赖密码的登录路径比如密钥认证、带外管理、虚拟机控制台有没有一个不参与锁定的紧急账户很多团队会保留一个break-glass账号或者确保至少一个sudo用户不触发even_deny_root锁定策略是全局生效还是按SSH/桌面/RDP区分如果全局生效误伤面就太大。把这些想清楚了账户锁定才能真正成为安全防线而不是事故源。我自己的习惯是每台机器做完基线后都会实际锁定一次、解锁一次确认逃生通道有效才收工。这个过程花不了10分钟但能避免很多半夜被叫醒的场景。账户锁定与防暴力破解机制说到底就是一个把门槛抬高的事攻击者要付出更多时间成本而管理员自己始终保留一条能进去的路。配置PAM、设置参数、测试锁定与解锁、准备恢复方案这一串动作做完整才算真正把机制用起来了。
阅读完成 · 觉得有帮助?
咨询建站