Akemi

Linux软件防火墙-PAM模块

2026/02/11

PAM是Sun公司在1995年开发的,目前是linux/unix的核心认证框架,全称为可插拔认证模块,一般是开发比较关心

PAM已经提前整合了各类认证库,比如本地密码库,ssh密钥库。核心目的是将认证功能和应用程序解耦,无需内置复杂的认证逻辑,只需要调用PAM接口就可以实现多样化的身份验证需求

1
2
3
4
5
6
7
8
# pam认证原理
应用程序(sshd) → PAM核心库(libpam.so) → PAM配置文件/etc/pam.d/应用名 → PAM模块(pam_unix.so)

工作层次:
应用程序层:发起认证请求,如用户登录、sudo,执行PAM提供的标准api
PAM核心库层:解析应用对应的PAM配置文件,按规则加载/执行PAM模块,协调模块执行顺序,汇总模块返回结果
配置文件层:定义"应用程序应使用哪些模块","模块执行顺序","模块结果如何影响整体认证"
模块层:实现具体认证功能

PAM配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
存储路径/etc/pam.d/
每个应用程序对应一个同名配置文件,如sshd对应/etc/pam.d/sshd

所有者/组必须为root:root
文件权限建议644

每条规则行的格式为:
type control module-path module-arguments

比如:
cat /etc/pam.d/crond
auth include system-auth
account required pam_access.so
account include system-auth
session required pam_loginuid.so
session include system-auth

type类型值:
1.auth
身份认证(你是谁) 典型模块pam_unix.so pam_ssh.so
用以比如sshd登录、su切换用户时使用

2.account
账户有效性检查(你有权限吗) 典型模块pam_unix.so pam_time.so
用以限制过期账户登录、工作时间登录

3.password
密码管理(修改密码等) 典型模块pam_cracklib.so pam_unix.so
用以比如passwd命令、首次登录强制修改密码

4.session
会话管理(登录、登出前辅助操作) 典型模块pam_cracklib.so pam_unix.so
用以记录登录日志、设置用户最大进程数

control控制标志:(定义结果联动逻辑)
核心作用,决定模块的执行结果如何影响当前和后续
1.required
模块必须成功,否则当前阶段失败,但会执行后续模块,比如核心认证模块

2.requisite
模块必须成功,否则终止当前阶段
用于关键校验

3.sufficient
模块成功则当前阶段直接通过,后续模块不再执行;失败就继续执行

4.option
模块结果不影响当前阶段

5.include
引入其他配置文件的所有规则

6.substack
引起其他配置文件的规则,但视为子栈,失败仅终止子栈,父栈继续执行

module-path模块路径:指定要加载的pam模块
常用内置模块:
pam_unix.so 本地密码认证、账户检查、密码更新
pam_cracklib.so 密码强度检查
pam_tally2.so 登录失败次数限制
pam_time.so 登录时间限制
pam_listfile.so 用户、终端黑白名单控制

module-argument 模块参数:
为pam模块传递自定义参数,调整模块的执行规则,参数需与模块
pam_unix.so: unllok允许空密码、shadow读取/etc/shadow密码、use_authtok 复用前一模块密码
例: auth required pam_unix.so nullok (允许空密码登录)

pam_cracklib.so: retry=3 密码强度检查可重试3次
例: password requisite pam_cracklib.so retry=3 minlen=8

pam_tally2.so: deny=5 连续五次失败锁定 unlock_time=300 锁定300秒 even_deny_root 适用root
例: auth required pam_tally2.so deny=5 unlock_time=300

pam_time.so 依赖于/etc/security/time.conf的时间规则
例: account required pam_time.so

**通用配置文件common-*(**复用规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
系统默认在/etc/pam.d/提供4个通用配置文件,用于存储所有应用共享的认证规则,避免重复编写

1.
common-auth
common-account
common-password 共享的password阶段规则
common-session 共享的session阶段规则

2.使用include复用
auth include common-auth # 引入通用密码认证规则

3.实例:auth-common
# 通用认证规则
auth [success=1 default=ignore] pam_unix.so unllok_secure
auth requisite pam_deny.so
auth required pam_permit.so

pam_unix.so认证成功时跳过后续一个模块,失败则忽略
pam_deny.so 拒绝所有请求(当第一条失败后执行)
pam_permit.so 允许认证,当第一条成功后执行

PAM的实战

配置密码复杂度策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
查看当前使用的策略
cat /etc/pam.d/passwd
#%PAM-1.0
# This tool only uses the password stack.
password substack system-auth
-password optional pam_gnome_keyring.so use_authtok
password substack postlogin
可以看到使用的password策略是system-auth

# 查看system-auth配置文件,可以看到使用的是pam_pwquality.so
cat /etc/pam.d/system-auth
...
password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=

# 修改pam_pwquality的配置
/etc/security/pwquality.conf

参数说明:
# 密码最小长度(默认:9)
minlen = 12

# 旧密码中必须有多少字符不在新密码中(默认:5)
difok = 7
# 负数表示最少需要,正数表示可以抵消长度要求

# 至少需要1个数字
dcredit = -1
# 至少需要1个大写字母
ucredit = -1
# 至少需要1个小写字母
lcredit = -1
# 至少需要1个特殊字符
ocredit = -1

# 必须包含的字符类别数(数字、大写、小写、特殊)
minclass = 3 # 至少需要3种不同类型的字符
# 检查密码是否包含用户名(正序或倒序)
usercheck = 1 # 1=启用,0=禁用(默认:0)
# 是否强制执行策略(1=强制执行,0=仅建议、告警)
enforcing = 1
# 允许重试3次(默认:3)
retry = 3
# 是否只对本地用户生效,0=所有用户,1=仅本地用户
local_users_only = 0
# 是否对root用户强制执行
enforce_for_root = 1 # 1=root也强制,0=root豁免

配置限制特定用户只能从特定IP登录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 查看pam_access模块是否存在
ls /lib*/security/pam_access.so
/lib64/security/pam_access.so

# 确保ssh使用了PAM(默认使用)
grep -r PAM /etc/ssh | grep -v '#'
/etc/ssh/sshd_config.d/50-redhat.conf:UsePAM yes

# 配置sshd的pam
vim /etc/pam.d/sshd
第一行插入(目的是,在sshd密码认证之前,对其做IP层面的限制)
auth required pam_access.so

# 配置access模块的访问控制列表
vim /etc/security/access.conf
+:ws:ALL # 允许ws从任何网络登录
+:xhy:192.168.10.0/24 # 允许xhy从192.168.10.0/24登录
+:xhy:10.0.0.1 # 允许xhy从特定IP 10.0.0.1登录
+:@wangsheng:10.0.0.0/24 # 允许wangsheng组的用户从该网段登录
-:ALL:ALL # 拒绝其他所有用户的登录(没有匹配+的规则)

基于PAM实现用户登录失败次数限制(防暴力破解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 确认模块是否存在
find / -name pam_faillock.so
/usr/lib64/security/pam_faillock.so

# 配置pam的配置文件
vim /etc/pam.d/password-auth
4 auth required pam_env.so
5 auth required pam_faillock.so preauth silent audit deny=5 unlock_time=120
6 auth sufficient pam_unix.so try_first_pass nullok
7 auth [default=die] pam_faillock.so authfail audit deny=5 unlock_time=120
8 auth required pam_deny.so
9
10 account required pam_unix.so
11 account required pam_faillock.so

12 password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=
13 password sufficient pam_unix.so try_first_pass use_authtok nullok sha512 shadow
14 password required pam_deny.so
15
16 session optional pam_keyinit.so revoke
17 session required pam_limits.so
18 -session optional pam_systemd.so
19 session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
20 session required pam_unix.so

第5和7和11是新添加的
5:检查用户账户是否已被锁定,如果账户已锁定(之前失败5次),直接拒绝访问
7:记录失败次数,达到5次就锁定账户120秒
11:再次验证账号是否是锁定状态
参数 作用 示例
preauth 在认证前检查账户是否已锁定 如果已锁定,直接拒绝
silent 静默模式,不显示过多信息 避免给攻击者提示
audit 记录详细日志到系统日志 便于审计和监控
deny=5 允许连续失败的次数 5次失败后锁定
unlock_time=120 锁定时间(秒) 120秒=2分钟
authfail 认证失败后执行 密码输入错误后计数器增加

配置用户会话资源限制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 确认模块是否存在
find / -name pam_limits.so
/usr/lib64/security/pam_limits.so

# 添加配置,配置文件末尾添加
vim /etc/pam.d/sshd
session include pam_limits.so

# 调整limits模块参数
vim /etc/security/limits.conf
配置文件格式:
<username> <type> <item> <value>

<username>(适用对象)
用户名:如 john。
组名:格式为 @groupname,如 @developers。
通配符 *:代表默认限制,适用于所有未明确指定的普通用户

<type>(限制类型)
soft:软限制。用户可以超过这个值,但不能超过 hard 限制。通常作为默认值,用户可以通过 ulimit 命令自行上调。
hard:硬限制。由系统管理员设定,是用户调优的物理上限。只有 root 用户可以增加硬限制。
-:表示同时设定 soft 和 hard 为相同的值。

<item>(限制资源项)
nofile 单个进程可以打开的最大文件句柄数(最常用)。
nproc 该用户可以创建的最大进程数。
memlock 最大可锁定在内存中的地址空间 (KB)。
stack 最大栈大小 (KB)。
cpu 最大 CPU 时间(分钟)。
fsize 用户可创建的最大文件大小 (KB)。
maxlogins 该用户或组允许的最大并发登录数。
as 进程可占用的最大虚拟内存(地址空间)大小 (KB)。

<value>(限制值)
根据 <item> 的不同,单位可能是 KB、分钟或纯数字

配置示例(后面的规则会覆盖前面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 核心转储大小
* hard core 0 # 禁止生成core文件
* soft core 10000 # core文件最大100MB

# 内存限制
* hard rss 500000 # 物理内存500MB
* hard data 200000 # 数据段大小200MB
* hard stack 100000 # 栈大小100MB

# 进程限制
* hard nproc # 最多100个进程
* hard maxlogins 3 # 最多三个同时登录

# 所有用户默认限制
* soft nproc 1024
* hard nproc 4096
@staff hard nproc 10000

# 组限制
@dev hard nofile 5000

这里的limits.conf与ulimit与systemd(cgroup/sysctl)的区别

  • ulimit只对当前 Shell 进程及其产生的子进程
  • limits.conf(pam模块)在用户登录时,会自动帮你执行类似 ulimit 的操作
  • sysctl设置的是整个系统的限制,不分用户
  • systemd(cgroup)作用于具体的服务单元 (Service Unit)
CATALOG
  1. 1. PAM配置文件
  2. 2. PAM的实战
    1. 2.1. 配置密码复杂度策略
    2. 2.2. 配置限制特定用户只能从特定IP登录
    3. 2.3. 基于PAM实现用户登录失败次数限制(防暴力破解
    4. 2.4. 配置用户会话资源限制