等保测评报告里最常出现的“操作系统未设置口令有效期策略”“口令复杂度策略不满足要求”这两条,我在方德系统的整改现场见了太多次。方德是基于Debian的国产Linux操作系统,日常运维和Debian/Ubuntu基本一致,但默认密码策略是真的“放养”:最短长度只有5位,不强制大小写、数字和特殊字符组合,口令不会过期,登录失败也没有锁定机制。等保三级里“身份鉴别”这个控制点,几乎每台机器都能挑出两三条不合规项。
这篇文章把方德系统上跟密码安全相关的三大策略一次讲透:密码复杂度、口令有效期、登录失败锁定。每个策略我会先讲清原理和文件位置,再给可复制的配置命令,最后补充改完为什么不生效、存量用户如何处理这类实操问题。文章按“最稳妥、最小影响”的顺序编排,正在做安全加固或等保整改的运维同学可以直接照着操作。
1. 动手前先摸清:方德的密码策略到底分散在几个文件里
1.1 先认识PAM,不然你只会在文件里乱翻
方德虽然带了图形化的用户管理界面,但安全加固讲究的是可复现、可审计,所以我建议全程命令行操作。要理解密码策略,第一课是PAM,全称 Pluggable Authentication Modules,可插拔认证模块。
你可以把PAM想象成机场安检通道:乘客要登机,必须依次通过证件核查、行李扫描、人身检查等环节,每个环节由不同的工作人员负责。Linux下用户登录、修改密码也是一样,认证过程会被拆成多个独立的小模块,按配置顺序依次执行,任一步骤不通过,整个流程就失败。
方德的PAM主配置在/etc/pam.d/目录下。和密码安全强相关的有三个文件,职责完全不同:
| 文件 | 控制阶段 | 典型模块 | 管理内容 |
|---|---|---|---|
/etc/login.defs | 用户创建/密码修改工具 | shadow套件 | 口令默认有效期、最小长度 |
/etc/pam.d/common-password | passwd修改口令 | pam_pwquality.so | 密码复杂度校验 |
/etc/pam.d/common-auth | 登录认证 | pam_faillock.so | 登录失败锁定 |
很多人只改了其中一个文件就以为改完了,结果测评一查还是不合规,问题往往就出在没搞清这三个文件的边界。/etc/login.defs管的是“默认值”,common-password管的是“改密码时符不符合复杂度”,common-auth管的是“登录时失败多少次锁定”。三件事必须分别配置。
1.2 修改前先备份、再摸现状
动手之前,我习惯先看一眼当前状态,顺便确认系统里已经装了哪些模块。执行这几条命令:
cat /etc/os-release dpkg -l | grep -E 'libpam-pwquality|libpam-modules' grep -E '^PASS_' /etc/login.defs ls /lib/x86_64-linux-gnu/security/ | grep -E 'pwquality|faillock|tally2'输出怎么看:如果dpkg结果里没有libpam-pwquality,说明系统连密码质量模块都没装,后面要先装包;如果 security 目录里没有pam_faillock.so,只有pam_tally2.so,说明系统PAM版本较老,锁定策略要用 tally2 的写法。方德不同版本差异比较明显,先摸清环境再动手,能避免后面一半的坑。
备份命令也在这里一起做掉:
cp /etc/login.defs /etc/login.defs.bak-$(date +%Y%m%d) cp /etc/pam.d/common-password /etc/pam.d/common-password.bak-$(date +%Y%m%d) cp /etc/pam.d/common-auth /etc/pam.d/common-auth.bak-$(date +%Y%m%d)1.3 理解所见即所得的验证方式
还有一个习惯我要啰嗦一句:PAM配置不像其他服务有语法检查工具,改错了通常不会立刻报错,而是等你断开SSH之后再也没法登录。所以后面每一步,我都建议你用“新开一个SSH会话试一下”作为验证手段,而不是关掉当前窗口等结果。这是做系统加固最基本的安全操作,能救你无数次。
2. 密码复杂度:pwquality参数与PAM挂载的完整链路
2.1 pwquality.conf里每个参数到底是什么意思
方德默认的密码复杂度模块是pam_pwquality,对应配置文件/etc/security/pwquality.conf。网上很多教程让你照抄一堆参数,却没讲清楚参数之间的关系,导致排查时一头雾水。核心参数就五个:
minlen:密码最小长度,单位是字符;dcredit:数字字符的“信用分”;ucredit:大写字母的信用分;lcredit:小写字母的信用分;ocredit:特殊字符的信用分。
这里最反直觉的是 credit 的取值逻辑。正值表示“最多只算几个,其余不参与长度累加”,负值表示“该类别至少需要几个”。实际等保整改时,我们要求密码至少8位、包含大小写字母、数字和特殊字符中的三类以上,惯用配置是四类全都要,所以四个 credit 都设成 -1,minlen 设成 8。
很多人会误解成minlen=8加上四类 credit 全部 -1,密码长度就得12位往上。其实不是这样。这里的计算方式是:minlen 是密码实际字符长度的底线,每个负值 credit 只强制要求对应类别至少出现1次,而不是叠加到 minlen 上。设一个Abc123!@,刚好8位,四类齐全,就能通过;设Abc12345,也是8位,但缺特殊字符,会被拒绝。与其对着文档推导,不如改完配置后拿几组测试密码试一遍,最直观。
2.2 编辑配置文件
vi /etc/security/pwquality.conf在文件末尾追加以下内容:
minlen = 8 dcredit = -1 ucredit = -1 lcredit = -1 ocredit = -1 retry = 3retry = 3表示用户设置密码时最多允许尝试3次,超过就报错。还有一行默认被注释的enforce_for_root,取消注释后 root 用户改密码也受复杂度限制。我建议根据你的管理方式决定:如果经常用 root 直接改密码,先不要开,避免把自己卡在门外。
但到这里还没完,配置文件只是模块的行为参数,模块自己得先挂载到认证栈上才会被调用。
2.3 挂载到common-password
先看当前/etc/pam.d/common-password的典型内容:
password [success=1 default=ignore] pam_unix.so obscure yescrypt password requisite pam_deny.so password required pam_permit.so我们要把pam_pwquality.so放到pam_unix.so之前:
password requisite pam_pwquality.so retry=3 password [success=1 default=ignore] pam_unix.so obscure yescrypt password requisite pam_deny.so password required pam_permit.so为什么必须放在pam_unix.so前面?因为 passwd 修改密码时各模块按顺序执行,pam_pwquality 先检查新密码是否符合复杂度规则,检查通过后才交给 pam_unix 去写 shadow 文件。顺序反了,密码已经写进去了再被拒绝,可能导致状态不一致。
需要注意,老版本方德的pam_unix.so那行哈希算法可能是sha512,保持原样,不要改成yescrypt,除非你确认内核和PAM版本都支持。哈希算法不一致会导致旧密码验证失败,这是一个很隐蔽的坑。如果系统里没有libpam-pwquality包,需要先安装:
apt update apt install libpam-pwquality2.4 实战验证
配置完成后,用普通用户执行passwd,或者用 root 执行passwd 用户名实测几组密码:
12345678:长度8,但不含大小写字母组合、特殊字符,直接拒绝;Abc12345:长度8,有大小写和数字,但缺特殊字符,拒绝;Abc123!@:长度8,四类齐全,通过。
每次尝试后看日志:
grep pwquality /var/log/auth.log如果看到类似password is too simple的报错,说明模块已经生效。如果日志里什么都没有,大概率是模块没挂载上,或者改错了文件。另外,方德桌面系统图形界面修改密码时同样会走PAM栈,所以命令行改完,图形界面也会同步生效,不用担心两套策略不一致。
3. 密码有效期:/etc/login.defs只是起点,存量用户才是大头
3.1 login.defs里改的三个值及含义
密码复杂度解决的是“密码容不容易被猜中”,有效期解决的是“密码被猜中后能用多久”。等保三级通常要求口令最长使用期限不超过90天,最短使用期限不少于7天,提前警告期不少于7到14天,具体以测评机构要求为准。对应到/etc/login.defs里就是三行:
PASS_MAX_DAYS 90 PASS_MIN_DAYS 7 PASS_WARN_AGE 14修改后,通过useradd新建的用户会自动继承这三个值。但这里有一个关键坑:/etc/login.defs只对新建用户生效,对已经存在的存量用户不会自动刷新。换句话说,你在一台跑了大半年的服务器上改完 login.defs,老用户密码的有效期还是“永不失效”。等保测评检查的是实际用户状态,不是检查配置文件,只改这个文件评测得0分的情况我见过太多次。
3.2 用chage批量补齐存量用户
手动改存量用户的命令是chage,记住三个参数即可:
chage -M 90 -m 7 -W 14 用户名-M是密码最长使用天数,-m是最短修改间隔,-W是到期前警告天数。改完用chage -l 用户名验证,输出里会出现Maximum number of days between change : 90这样的信息。
一台服务器上用户可能有几十个,手动敲不现实,我一般这样批量处理:
for user in $(awk -F: '$3>=1000 && $3<60000 {print $1}' /etc/passwd); do chage -M 90 -m 7 -W 14 "$user" done这条命令的筛选逻辑是取出 UID 在1000到59999之间的账号,这些是普通用户。系统用户密码的有效期不需要管,因为它们多数是/sbin/nologin或由服务调用,强制改密反而可能影响服务启动。如果你有特殊业务账号需要排除,可以在命令后面加白名单:
for user in $(awk -F: '$3>=1000 && $3<60000 {print $1}' /etc/passwd | grep -vE '^(nobody|testuser)$'); do chage -M 90 -m 7 -W 14 "$user" done还要注意,如果用户在/etc/shadow里的密码字段是!或*,说明该账户没有可用密码,chage 操作不影响;如果状态是LK,说明账户已经锁定,也不需要处理有效期。
3.3 顺手设置首次登录强制改密
chage -d 0也是一个很有用的参数,它会把用户的“最后修改密码时间”归零,用户下次登录时系统会强制要求设置新密码。我通常在开通账号时这样用:
useradd -m -s /bin/bash zhangsan echo 'Temp@12345' | passwd --stdin zhangsan chage -d 0 zhangsan管理员先设一个临时初始密码,员工第一次登录必须改成自己的密码,这样管理员也不知道员工实际使用的密码。但这里要提醒一句:如果服务器同时配置了登录失败锁定策略,员工可能因为不知道需要改密而多次输错临时密码导致账户被锁。开通账号时一定要把初始密码和“首次登录需要改密”的规则同步告知,不然运维的工单会多到爆。
3.4 PASS_MIN_DAYS为什么不能设成0
有人觉得只设PASS_MAX_DAYS就行,PASS_MIN_DAYS设成0省事。这其实是给安全打了个大折扣。如果没有最短修改间隔,用户可以第一天把密码改成新密码,第二天又立刻改回旧的123456,那90天有效期就名存实亡了。把PASS_MIN_DAYS设为7,意味着密码至少要用7天才能再改,能有效防止“改密-改回”的循环。同样,PASS_WARN_AGE设成7到14天,是给用户留出缓冲,避免口令到期当天才发现登不进去,然后大半夜打电话找你重置。
改完之后,别忘了chage -l抽查几个用户,确认批量命令真的执行成功了。
4. 登录失败锁定:pam_faillock的三行配置与解锁方式
4.1 先确认你的方德版本该用哪个模块
登录失败锁定是对抗暴力破解最直接的手段。等保要求通常是连续失败5次锁定账户,锁定时间建议15分钟左右。方德基于Debian,老版本默认装的是pam_tally2,新版本已经转向pam_faillock。两个模块的状态目录和操作命令都不同,配置前先确认:
ls /lib/x86_64-linux-gnu/security/ | grep -E 'tally2|faillock'如果两个都有,优先用pam_faillock。原因有二:第一,根据我的经验,tally2 在某些版本里对SSH登录失败类型的区分不如 faillock 细致,容易误伤正常用户;第二,faillock 提供了faillock命令,查状态、手动解锁都比 tally2 直观得多。
4.2 common-auth 的完整配置
编辑/etc/pam.d/common-auth,在文件最前面加三行,原始内容保持不动。一个典型的修改后文件是这样:
auth required pam_faillock.so preauth audit deny=5 unlock_time=900 even_deny_root auth [default=die] pam_faillock.so authfail audit deny=5 unlock_time=900 even_deny_root auth sufficient pam_faillock.so authsucc audit deny=5 unlock_time=900 even_deny_root auth [success=1 default=ignore] pam_unix.so nullok auth requisite pam_deny.so auth required pam_permit.so逐行解释一下这三行的作用:
- 第一行
preauth:在认证开始前先检查该用户是否已经被锁定。如果已锁定,直接拒绝,不再调用后续模块; - 第二行
authfail:用户输错密码后,在这里记录失败次数并比对 deny 阈值,达到阈值就锁定; - 第三行
authsucc:认证成功时调用,清除该用户已有的失败计数。
三个deny=5、unlock_time=900参数必须完全一致,否则会出现“提示锁定但实际还能登录”的诡异情况。
最容易踩的坑是模块顺序:这三行必须放在pam_unix.so之前。如果preauth被放到文件末尾,前面 pam_unix 已经判定认证成功,faillock 的锁定检查根本不会执行,配置等于白做。放在前面的核心目的,是让每一次认证失败先经过它的计数,每一次认证成功也经过它的清除逻辑。
4.3 参数怎么定
参数建议值参考这张表:
| 参数 | 建议值 | 说明 |
|---|---|---|
deny | 5 | 连续失败5次锁定账户 |
unlock_time | 900 | 900秒,即15分钟 |
audit | 无 | 记录审计日志,方便回溯 |
even_deny_root | 视情况 | 是否对 root 也生效,谨慎开启 |
特别说明even_deny_root。加上它 root 也会被锁,如果管理员平时只通过SSH远程管理,连续输错5次后 root 会被锁15分钟,没有其它应急通道的话等于把自己关在门外。我的建议是:有 KVM、物理控制台或者其他免密通道的,可以加上;否则先不加,等应急通道准备好再说。
4.4 测试和手工解锁
测试流程我建议严格按下面步骤走,避免把生产环境搞挂:
- 打开两个SSH会话,其中一个保持 root 登录态不要动,否则测试把自己锁了就进不去了;
- 用普通用户故意输错密码5次;
- 第6次输入正确密码,观察是否提示账户已锁定;
- 用
faillock --user 用户名查看失败计数; - 解锁执行
faillock --user 用户名 --reset; - 查看
/var/log/auth.log里的 faillock 记录,确认事件可追溯。
如果确实把自己锁了,而且系统里没有其他管理通道,最稳妥的办法是去物理控制台登录后执行faillock --reset,或者删除/run/faillock/目录下对应的用户状态文件。删除状态文件也是一种解锁方式,但不如 faillock 命令正规,应急用一下可以。
5. 等保合规视角的批量复查与排障经验
5.1 一条命令快速摸清现状
整改做完不是终点,测评前还要能快速自查。我每次交付前都会跑一段脚本,把所有相关策略一次性拉出来,既当自查又当审计留证:
echo "===== OS Version =====" cat /etc/os-release | grep PRETTY_NAME echo "" echo "===== password complexity =====" grep -E 'minlen|dcredit|ucredit|lcredit|ocredit' /etc/security/pwquality.conf echo "" echo "===== password aging (login.defs) =====" grep -E '^PASS_MAX_DAYS|^PASS_MIN_DAYS|^PASS_WARN_AGE' /etc/login.defs echo "" echo "===== actual aging for normal users =====" for user in $(awk -F: '$3>=1000 && $3<60000 {print $1}' /etc/passwd); do echo "--- $user ---" chage -l "$user" | grep -E 'Last password change|Maximum|Minimum|Expires' done echo "" echo "===== lock & complexity module =====" grep -rE 'pam_faillock|pam_pwquality' /etc/pam.d/common-auth /etc/pam.d/common-password这套“三件套”覆盖了复杂度、有效期、锁定三大块,测评前来一遍心里基本有底。
5.2 常见坑:为什么改完不生效
- 配置了pwquality但密码还能设简单密码:优先查
pam_pwquality.so是否真的挂载进了common-password,而且必须在pam_unix.so之前。另外确认libpam-pwquality包确实装了,否则模块加载会静默失败。 - 改完login.defs但存量用户不生效:这是最普遍的问题。
/etc/login.defs只是新建用户的默认模板,存量用户的到期时间要以chage -l的显示为准。批量改完务必抽查。 - faillock配置后所有用户开始异常:大概率是
common-auth里三行 faillock 的顺序或者参数写错了。常见错误是 preauth 行放在了 pam_unix 之后,锁定检查执行不到;或者是 authfail 行的[default=die]写成了required,导致认证流程提前终止。 - 模块有多个配置文件目录:有些方德版本还支持
/etc/security/pwquality.conf.d/目录,里面的配置优先级可能更高。改了半天不生效的话,看看这个目录下有没有被其他配置覆盖。 - 测试密码时一定要用普通用户:用 root 测试有时会因为 PAM 对 root 的特殊处理得到不符合预期的结果,而且频繁测试弱密码还会在审计日志里留下一堆
FAILED_PASSWORD记录,影响日志美观。
5.3 备份、回滚和审计留痕
文章开头我让你先备份,这是有原因的。PAM 配置如果没有经过充分测试就上生产,回滚几乎是唯一的后悔药。备份文件名建议带上日期:
cp /etc/pam.d/common-auth /etc/pam.d/common-auth.bak-20250101 cp /etc/security/pwquality.conf /etc/security/pwquality.conf.bak-20250101 cp /etc/login.defs /etc/login.defs.bak-20250101回滚直接覆盖回去即可,但覆盖后同样要开一个新 SSH 会话验证登录正常,再关掉旧会话。这个操作习惯能让你避免“回滚后还是进不去”的尴尬。
关于审计留痕,等保整改不只是改配置,还要能拿出证据。建议把执行过的命令、备份文件名、chage 检查输出、faillock 配置结果整理成一份加固记录,测评机构复核时可以直接对照,省去很多口头解释。
5.4 策略别设到反人性的程度
最后说一个安全加固中特别容易走偏的点:复杂度策略不要设得过于苛刻。我见过有单位把密码要求设成minlen=16加四类全必须,结果员工根本记不住,只能把密码写在便利贴上贴在显示器边框。密码策略的本质是通过提高攻击成本来保护资产,如果设到了用户必须用明文记录才能记住的程度,那它反而成了新的安全漏洞。等保三级的要求是8位以上、包含三类字符组合,这个强度在多数场景下是够用的,没必要擅自加码。
我在实际项目里的习惯是:所有加固策略先在测试机完整验证一轮,再批量推到生产环境。执行的时候保持多个SSH会话,改一步验证一步,绝不一次性把三个文件全改完再测试。安全加固这件事,慢一点不要紧,把自己锁在门外才是真的尴尬。如果这篇文章里的某个步骤在你们的环境里表现不太一样,大概率是方德版本差异导致的,先按第5.2节的思路排查,多半能定位到原因。