Linux服务器安全加固:PAM认证与密码策略实战指南
2026/7/21 17:36:24 网站建设 项目流程

1. 项目概述:从“门锁”到“保险柜”的服务器安全观

每次和运维同行聊起服务器安全,大家的第一反应往往是“防火墙配好了吗?”、“端口关了吗?”。这没错,防火墙就像是服务器的大门,把守着网络层面的第一道防线。但今天我想聊点更深层的:当攻击者已经站在了你的“家门口”,甚至拿到了一个低权限的账户,你靠什么阻止他登堂入室?答案很可能就藏在最基础、也最容易被忽视的密码策略和其背后的PAM(Pluggable Authentication Modules,可插拔认证模块)机制里。

我们花大价钱部署了WAF、IDS,却常常对系统自带的、免费的、且威力巨大的认证安全模块视而不见。一个弱密码,足以让所有外围防御形同虚设。这个项目,就是一次对Linux服务器认证体系的内核级加固实战。它不仅仅是修改几个密码复杂度参数,而是通过PAM模块,构建一套从密码强度、登录尝试限制、到会话管理的立体化认证防线。我会带你从原理到实操,一步步拆解如何让你的服务器安全从“装了个好门锁”升级到“配备了生物识别、动态密码和入侵警报的智能保险柜”。

2. 核心需求解析:为什么防火墙之后,密码策略是命门?

在深入技术细节前,我们必须先达成一个共识:安全是一个链条,其强度取决于最薄弱的一环。防火墙和网络策略解决了“谁能敲门”的问题,而PAM和密码策略解决的是“谁有钥匙,以及钥匙怎么用”的问题。

2.1 认证环节的典型攻击场景

想象一下这些场景,它们每天都在互联网的阴影下发生:

  1. 暴力破解:攻击者利用自动化工具,对SSH、FTP、Web登录接口等进行海量用户名/密码组合尝试。如果密码简单(如123456password、公司名+年份),被攻破只是时间问题。
  2. 密码喷洒:与暴力破解相反,攻击者使用几个常用密码(如Summer2024!,Welcome1),去碰撞大量的用户名。这种攻击针对那些有统一弱密码策略的组织尤其有效。
  3. 凭证填充:利用从其他网站泄露的账号密码库,在目标服务器上尝试登录。很多人习惯在不同平台使用相同密码,导致一处泄露,全网遭殃。
  4. 会话劫持与持久化:攻击者通过某种方式获取了一个有效的会话,或者植入了一个后门账户,试图维持其访问权限。

一个健壮的密码策略和PAM配置,正是为了系统性地应对上述威胁。它的核心需求可以归纳为三点:提高密码的猜测难度增加连续猜测的成本和风险监控和限制异常认证行为

2.2 传统密码策略的局限性

很多管理员对密码策略的理解,还停留在/etc/login.defs里修改一下PASS_MAX_DAYS(密码最长有效期)和PASS_MIN_LEN(密码最小长度)。或者,使用chage命令管理一下用户密码过期时间。这些措施是必要的,但远远不够。它们存在几个关键短板:

  • 被动且静态:只在密码创建或修改时检查,无法应对实时的暴力破解攻击。
  • 缺乏智能响应:无法根据登录失败频率、来源IP等动态信息做出反应(如临时封禁)。
  • 维度单一:主要关注密码本身(长度、复杂度),对认证过程(如尝试频率、时间、地点)控制力弱。
  • 无法深度集成:难以与其他安全工具(如日志分析系统、入侵检测系统)进行灵活联动。

而这,正是PAM模块大显身手的地方。PAM将认证过程模块化、可编程化,允许我们以极高的灵活度定义“一次成功的登录究竟需要满足多少条件”。

3. PAM模块深度解析:Linux认证的万能插座

理解PAM,是进行一切高级认证配置的前提。你可以把它想象成服务器认证系统的一个“万能插座板”。

3.1 PAM是什么?架构与流程

PAM的核心思想是将应用程序(如login,sshd,su)与具体的认证机制(如密码、指纹、令牌)解耦。应用程序不再需要关心用户是用密码登录还是用密钥登录,它只需要向PAM库发起一个请求:“请帮我认证这个用户。” PAM则根据一套预定义的规则(配置文件),调用一系列模块来完成认证工作。

一个典型的PAM认证流程涉及四种模块类型,按顺序执行:

  1. auth(认证):核实用户身份。例如,提示输入密码并与/etc/shadow中的哈希值比对。
  2. account(账户):检查账户本身是否有效。例如,账户是否过期、当前时间是否允许登录、是否达到最大用户数限制。
  3. password(密码):负责更新用户的认证令牌(如修改密码)。
  4. session(会话):在用户认证成功前后,进行会话管理和资源设置。例如,记录登录日志、挂载用户目录、设置环境变量。

PAM的配置文件通常位于/etc/pam.d/目录下,每个需要认证的服务都有一个对应的文件(如/etc/pam.d/sshd,/etc/pam.d/login)。文件由一行行的“规则”组成,每条规则定义了在什么条件下调用哪个模块。

3.2 关键PAM模块介绍

在安全加固中,我们会频繁使用以下几个核心模块:

  • pam_unix.so / pam_pwquality.so (旧版为pam_cracklib.so):这是密码复杂度检查的基石。pam_pwqualitypam_cracklib的增强版,提供了更精细的密码策略控制,如必须包含的字符类别、拒绝常见弱密码等。
  • pam_tally2.so:这是防御暴力破解的利器。它能够统计用户登录失败的次数,并在达到阈值后锁定账户一段时间。注意:在一些新发行版(如较新的Fedora、RHEL 8+)中,pam_faillock模块正在取代pam_tally2,两者功能类似但配置方式略有不同,下文会分别说明。
  • pam_limits.so:限制用户会话所能使用的系统资源,如最大进程数、打开文件数、内存等。这可以防止单个用户(或被攻陷的账户)发起资源耗尽攻击。
  • pam_time.so:基于时间的访问控制,可以限制用户只能在特定时间段(如工作日的工作时间)登录。
  • pam_access.so:基于主机名、IP地址或终端类型的访问控制,类似于/etc/hosts.allow/etc/hosts.deny,但集成在PAM流程中,更加灵活。
  • pam_lastlog.so:显示用户上次登录的时间和地点,有助于用户发现账户异常。
  • pam_securetty.so:限制root用户只能从安全的终端(tty)登录,通常禁止root通过网络(如ssh)直接登录,这是一个非常重要的安全实践。

理解每个模块的作用,就像拿到了工具箱里不同功能的工具。接下来,我们看看如何用这些工具来搭建我们的安全体系。

4. 立体化密码与认证策略实战配置

理论说得再多,不如一行配置。下面我们进入实战环节,我会以最常见的CentOS 7/RHEL 7(使用pam_tally2)和Ubuntu 20.04/RHEL 8(使用pam_faillock)为例进行对比演示。请根据你的系统选择对应的路径。

4.1 第一层防御:强化密码本身(pam_pwquality)

目标:强制用户设置高强度密码,从源头上减少被猜解的可能。

首先,确保系统安装了libpwquality工具和PAM模块:

# CentOS/RHEL sudo yum install libpwquality # Ubuntu/Debian sudo apt install libpam-pwquality

主要的配置文件是/etc/security/pwquality.conf。你可以直接编辑这个文件,或者通过pam_pwquality模块的参数在PAM配置中指定。我推荐直接修改配置文件,因为它更集中、清晰。

编辑/etc/security/pwquality.conf,以下是一些关键参数及其建议值:

# 密码最小长度,建议至少12位 minlen = 12 # 至少包含一个大写字母 (A-Z) minclass = 1 # 或者更精细地控制: # dcredit = -1 # 至少1位数字 # ucredit = -1 # 至少1位大写字母 # lcredit = -1 # 至少1位小写字母 # ocredit = -1 # 至少1位特殊字符 # 拒绝包含用户名的密码(正向和反向) usercheck = 1 # 拒绝包含`pass`等常见弱词汇的密码 badwords = deny_words.txt # 需要自己创建这个字典文件 # 新密码与旧密码至少需要不同的字符数 difok = 8 # 拒绝与/etc/passwd中GECOS字段(用户全名等)相似的密码 gecoscheck = 1 # 密码中相同字符连续出现的最大次数 maxrepeat = 3 # 检查密码是否是回文 palindrome = 1

实操心得minlen的设置需要平衡安全性与可用性。对于内部系统,12位是较好的起点。difok参数非常重要,它能防止用户只在旧密码后加个数字就了事。usercheckgecoscheck能有效防止社交工程类密码。

配置好后,需要在PAM的密码管理栈中启用它。编辑/etc/pam.d/system-auth(对于RHEL系)或/etc/pam.d/common-password(对于Debian系),找到关于pam_pwquality.so的行。在RHEL 7上,它通常已经存在:

password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=

确保这行没有被注释,且包含retry=3(允许3次重试)等参数。

注意:修改密码策略不会强制现有用户立即更改密码。你需要结合chage命令来管理。例如,强制所有用户下次登录时修改密码:sudo chage -d 0 用户名。或者设置密码最长有效期:sudo chage -M 90 用户名

4.2 第二层防御:动态阻击暴力破解(pam_tally2 与 pam_faillock)

目标:在密码可能被猜中的“过程中”进行干预,锁定攻击源。

方案A:针对使用pam_tally2的系统(如CentOS 7)

  1. 配置PAM:编辑/etc/pam.d/password-auth/etc/pam.d/system-auth(通常两者会互相包含,修改一个即可)。在auth部分的开头添加:

    auth required pam_tally2.so deny=5 unlock_time=600 even_deny_root root_unlock_time=300
    • deny=5:连续失败5次后锁定账户。
    • unlock_time=600:锁定600秒(10分钟)。
    • even_deny_root:root用户也受此规则限制。
    • root_unlock_time=300:root账户锁定300秒(5分钟),可与普通用户区别对待。
  2. 在account部分添加:在同文件的account部分添加:

    account required pam_tally2.so

    这一行负责检查账户是否已被锁定。

  3. 管理锁定状态

    • 查看所有用户失败次数:pam_tally2
    • 查看指定用户:pam_tally2 --user username
    • 解锁一个被锁定的用户:pam_tally2 --user username --reset

方案B:针对使用pam_faillock的系统(如RHEL 8/CentOS 8, Ubuntu 20.04+)

pam_faillock功能更强大,它将失败记录存储在/var/run/faillock/目录下,支持更复杂的策略。

  1. 配置PAM:编辑/etc/pam.d/password-auth/etc/pam.d/system-auth。在auth部分的开头添加:

    auth required pam_faillock.so preauth silent audit deny=5 unlock_time=600 auth [default=die] pam_faillock.so authfail audit deny=5 unlock_time=600

    auth部分的末尾(通常在pam_unix.sopam_sss.so之后)添加:

    auth sufficient pam_faillock.so authsucc audit deny=5 unlock_time=600

    account部分添加:

    account required pam_faillock.so
  2. 配置策略参数(可选,更推荐):创建或编辑/etc/security/faillock.conf,这是更现代的配置方式:

    deny = 5 unlock_time = 600 fail_interval = 900 # 统计失败次数的时间窗口为900秒(15分钟) root_unlock_time = 300 # root锁定时间稍短 audit # 审计日志 silent # 静默模式
  3. 管理锁定状态

    • 查看状态:faillock --user username
    • 解锁用户:faillock --user username --reset

踩坑记录pam_tally2的锁定是“内存中”的,重启系统后锁定会解除。而pam_faillock的锁定信息存储在磁盘上,重启后依然有效。这对于防护重启后仍持续的自动化攻击很有用。务必在测试环境先验证配置,否则可能把自己锁在外面。永远保持至少一个活跃的root或sudo会话窗口在进行此类配置,或者预先配置好基于密钥的SSH认证作为备用登录方式。

4.3 第三层防御:访问控制与资源限制

目标:从登录源头和会话资源上施加限制。

基于时间的访问控制(pam_time)编辑/etc/security/time.conf,语法如下:

服务;终端;用户;时间范围

例如,禁止developers组的用户在非工作时间通过sshd登录:

sshd;*;@developers;!Al0000-2400

这行规则表示:对于sshd服务,所有终端,developers组用户,在任何时间Al代表所有日期,0000-2400代表全天)都不允许!表示否定)登录。显然这是个禁止所有时间的例子,实际使用时需要更精细的时间段。例如,只允许工作日9点到18点登录:sshd;*;@developers;Wd0900-1800

然后,在/etc/pam.d/sshd文件中添加:

account required pam_time.so

基于来源的访问控制(pam_access)编辑/etc/security/access.conf,语法更直观:

permission : users : origins

例如,只允许来自内网网段192.168.1.0/24的用户通过SSH登录:

+ : ALL : 192.168.1.0/24 + : root : LOCAL # root允许从本地控制台登录 - : ALL : ALL # 拒绝其他所有

/etc/pam.d/sshd中添加:

account required pam_access.so

会话资源限制(pam_limits)编辑/etc/security/limits.conf/etc/security/limits.d/下的文件,可以限制用户打开文件数、进程数等,防止DoS。例如,限制webuser最多只能有100个进程:

webuser hard nproc 100

在PAM配置中,pam_limits.so通常已在session部分默认加载。

4.4 第四层防御:关键安全基线配置

这些是必须做的最低限度的安全配置。

  1. 禁止root直接SSH登录:编辑/etc/ssh/sshd_config,设置PermitRootLogin no。然后使用普通用户登录后susudo提权。
  2. 使用SSH密钥认证:彻底禁用密码认证,转向更安全的密钥认证。在sshd_config中设置PasswordAuthentication noPubkeyAuthentication yes
  3. 配置sudo超时:编辑/etc/sudoers(使用visudo命令),添加Defaults timestamp_timeout=5,表示sudo密码缓存5分钟,之后需要重新输入。
  4. 启用lastlog与securetty:确保/etc/pam.d/login/etc/pam.d/sshd中包含pam_lastlog.sopam_securetty.so(后者主要针对login服务),让用户登录时能看到上次登录信息,并限制root登录位置。

5. 配置验证、测试与监控

配置完成后,绝不能一配了之。必须进行严格的测试和持续的监控。

5.1 测试你的配置

  1. 开一个新的终端会话:这是铁律。永远不要在你唯一已登录的会话中测试认证锁定策略。
  2. 测试密码复杂度:尝试用弱密码(如abc123)修改密码,看是否被拒绝。
    passwd testuser
  3. 测试失败锁定
    • 使用一个普通用户,通过SSH或su连续输入错误密码。
    • 观察第6次(假设deny=5)是否被拒绝,并提示“Account locked due to X failed logins”。
    • 等待解锁时间过后,再次尝试登录是否成功。
    • 使用pam_tally2faillock命令查看失败记录。
  4. 测试访问控制
    • 从被禁止的IP段或时间段尝试SSH登录,验证是否被拒绝。
    • 检查/var/log/secure(RHEL)或/var/log/auth.log(Ubuntu)中的日志信息。

5.2 关键日志监控

认证相关的日志是安全审计的核心。主要关注:

  • /var/log/secure(RHEL/CentOS)/var/log/auth.log(Ubuntu/Debian):这里记录了所有PAM和SSH的认证事件。
  • /var/log/faillock/目录:如果使用pam_faillock,这里有详细的失败记录文件。

你应该配置日志监控工具(如logwatch,fail2ban,或者更专业的SIEM系统)来实时分析这些日志。一个简单的grep命令也能快速发现问题:

# 查看过去一小时内失败的SSH登录尝试 sudo grep \"Failed password\" /var/log/secure | grep \"$(date -d \'-1 hour\' +\'%b %d %H:\')\" # 查看所有被锁定的账户事件 sudo grep \"pam_tally2\|pam_faillock\" /var/log/secure | tail -20

5.3 使用fail2ban进行应用层联动防护

虽然PAM的pam_tally2/fail2ban能在系统层面锁定账户,但fail2ban这个工具可以做得更多。它监控日志文件,当发现来自同一IP的多次失败登录尝试后,会自动调用防火墙(如iptablesfirewalld)临时封禁该IP地址。这是一种在网络层进行的、更彻底的阻断。

安装与配置fail2ban

# CentOS/RHEL sudo yum install epel-release sudo yum install fail2ban # Ubuntu/Debian sudo apt install fail2ban

复制默认配置文件并创建本地配置:

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

编辑/etc/fail2ban/jail.local,启用SSH防护并调整参数:

[sshd] enabled = true port = ssh filter = sshd logpath = /var/log/secure # Ubuntu 改为 /var/log/auth.log maxretry = 5 bantime = 3600 findtime = 600
  • maxretry=5:5次失败后封禁。
  • bantime=3600:封禁3600秒(1小时)。
  • findtime=600:在600秒(10分钟)内统计失败次数。

重启服务并查看状态:

sudo systemctl enable --now fail2ban sudo fail2ban-client status sshd

个人体会fail2ban和PAM账户锁定是互补的。PAM锁定的是“用户名”,防止针对特定用户的密码喷洒;fail2ban封锁的是“IP地址”,防止来自单一源的暴力破解。两者结合,构成了认证防御的纵深。

6. 常见问题与排查技巧实录

在实际操作中,你肯定会遇到各种问题。下面是我总结的一些典型场景和解决方法。

6.1 问题排查清单

问题现象可能原因排查步骤与解决方案
修改PAM配置后,所有用户都无法登录(包括root)。1. PAM配置文件语法错误。
2. 添加了requiredrequisite控制标志的模块失败,导致整个栈失败。
黄金法则:永远在另一个已认证的会话中测试!
1. 检查/var/log/secure/var/log/auth.log中的具体错误信息。
2. 使用pam_tally2 --user root --resetfaillock --user root --reset尝试解锁root。
3. 通过服务器控制台(物理机或云平台的VNC)登录,回退错误的PAM配置。
用户密码符合策略但仍被拒绝。1.pam_pwquality的字典检查(badwords)或usercheck生效。
2. 密码历史策略(remember参数)拒绝重复使用旧密码。
3. 其他PAM模块(如pam_limits资源耗尽)意外失败。
1. 检查/etc/security/pwquality.conf中的badwords文件和usercheck设置。
2. 检查/etc/pam.d/system-authpam_unix.so是否包含remember=5之类的参数。
3. 查看认证日志,定位是哪个模块返回了失败。
pam_tally2不记录失败次数或锁定无效。1. PAM配置文件中模块顺序错误,pam_tally2未在认证栈开头。
2. 针对的服务(如sshd)的PAM配置文件(/etc/pam.d/sshd)未包含相关规则。
3. 系统使用了pam_faillock而非pam_tally2
1. 确认pam_tally2.so行在/etc/pam.d/password-authauthaccount部分正确添加。
2. 确认/etc/pam.d/sshd通过@include包含了system-authpassword-auth
3. 使用grep -r pam_tally /etc/pam.d/grep -r pam_faillock /etc/pam.d/确认系统实际使用的模块。
配置了pam_timepam_access但未生效。1. 规则语法错误。
2. 对应的PAM配置文件(如/etc/pam.d/sshd)中未添加pam_time.sopam_access.so
3. 规则中的用户组需要用@前缀。
1. 仔细检查time.confaccess.conf的语法,特别是分号、冒号分隔符。
2. 确认account required pam_time.sopam_access.so已添加到对应服务的PAM配置中。
3. 使用groups username命令确认用户所属组名,在规则中使用@groupname
fail2ban服务运行但未封禁IP。1.filter定义不正确,无法匹配日志中的失败信息。
2.logpath指向错误。
3. 防火墙规则(iptables/firewalld)未被正确调用。
1. 使用fail2ban-regex /var/log/secure /etc/fail2ban/filter.d/sshd.conf测试过滤器。
2. 确认logpath与系统日志路径一致。
3. 运行sudo fail2ban-client status sshd查看“Currently failed”和“Total banned”计数。检查防火墙规则sudo iptables -L -nsudo firewall-cmd --list-all

6.2 高级技巧与注意事项

  1. 配置的继承与覆盖:理解/etc/pam.d/下文件的包含关系至关重要。例如,在RHEL中,sshd通常会@include system-auth。这意味着修改system-auth会影响所有包含它的服务。如果你想只为SSH设置特殊的策略,应该直接修改/etc/pam.d/sshd,而不是system-auth

  2. 控制标志(Control Flags)的精髓:PAM规则行的第二个字段(如required,sufficient,optional)决定了模块失败或成功对整体认证结果的影响。

    • required:模块必须成功。失败会导致最终认证失败,但会继续执行栈中后续模块。
    • requisite:模块必须成功。失败会立即导致认证失败,后续模块不再执行。常用于关键检查(如pam_securetty)。
    • sufficient:模块成功则立即通过认证(忽略后面required的模块)。失败则忽略,继续执行。
    • optional:成功或失败仅作为参考,不影响大局。 错误地使用requisite可能导致合法用户因一个非关键模块失败而被提前拒绝,体验很差。
  3. 云服务器与控制台救援:在云平台(如AWS EC2, 阿里云ECS)上,如果你错误配置了PAM或SSH导致无法登录,不要慌张。所有主流云平台都提供了“VNC连接”或“救援模式”功能。你可以通过云控制台连接到服务器的虚拟控制台,就像坐在物理机前一样,然后修复配置。务必在首次配置前,测试并确保救援通道可用

  4. 自动化与版本管理:服务器安全配置应该像代码一样被管理。将你的/etc/pam.d/关键文件、/etc/security/*.conf文件、/etc/ssh/sshd_config等纳入配置管理工具(如Ansible, SaltStack)或至少用Git进行版本控制。这样可以在出错时快速回滚,也能保证环境的一致性。

安全加固从来不是一劳永逸的事情,尤其是认证安全,它直接面对外部冲击。定期审查日志、更新密码策略、根据威胁情报调整失败锁定阈值,是运维工作中不可或缺的一部分。从今天起,别再只盯着防火墙了,把你服务器的“内功”——PAM认证体系——好好修炼一番,这才是应对真正威胁的基石。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询