[TOC]

0x00 前言介绍

Q:什么是PAM?
答:PAM 的全称为可插拔认证模块(Pluggable Authentication Modules:简称 PAM /pæm/ ),Linux中的一种安全验证方式是基于模块化设计、具有可插入功能的一种独立于应用程序之外的验证方式;设计的初衷是将不同的底层认证机制集中到一个高层次的API中,从而省去开发人员自己去设计和实现各种繁杂的认证机制的麻烦。 PAM 机制最初由 Sun 公司提出,并在其 Solaris 系统上实现,后来各个版本的 UNIX 以及 Linux 也陆续增加了对它的支持。

Q:为什么要使用PAM?
描述:服务器的系统安全确实是一件让用户头痛的事情,比如下面所列问题常规的安全措施并不能妥善地解决特别是在应用之中。

  • 如何确保系统中使用应用程序或服务的用户确是用户本人?
  • 如何给这些用户指定限制访问服务的时间段?
  • 以及如何限制各种应用程序或服务对系统资源的使用率等等?
    如果没有 PAM 认证功能只能写在各个应用程序中,一旦要修改某个认证方法,开发人员可能不得不重写程序,然后重新编译程序并安装;有了 PAM 认证的工作都交给 PAM ,程序主体便可以不再关注认证问题了“ PAM 允许你进来,那你就进来吧。”
    在从RedHat系列发行版Linux 3.x(>=内核中)已经集成了PAM安全验证方式, 并且能够使用它来解决上面所示的相关问题;

PAM特点&功能:

  • 给程序的开发人员提供一套统一的认证接口, 即应用程序可以不需要集成验证功能;
  • 具有很大的灵活性可以通过它为应用程序自由选择需要使用的验证方式。
  • 增强 Linux 服务器的安全性能。

Q:如何使用PAM?
答:当 LINUX 服务器中的某个应用程序或服务需要使用 PAM 来进行验证时,只要此应用程序或服务支持 PAM 验证功能,就可以通过修改其相应的 PAM 配置文件(所有验证功能都是通过一些库文件来提供的)来配置相应的验证方式,当重新启用些服务或应用程序时 PAM 模块就会通过其专用 API 来读取它的配置文件,根据配置文件中的内容来提供相应的验证功能;

我们先用一个例子来直观感受一下 PAM:

su 是一个很常用的 Linux 命令,可以让我们从一个用户切换到另一个用户。我们都知道,当用户使用 root 账号登录时,su 到别的用户是不需要密码的,而从其他用户 su 到 root 则需要输入密码。在用 su 命令切换用户的过程中, su 做了两件事:认证(是否是 root、不是 root 的话是否有目标用户的密码)和启动相应的 Shell。

让我们来关注一下 su 的认证功能。按照正常的逻辑, su 的开发人员很可能会自己写出认证的功能:先判断是不是 root,是则判定认证通过;不是则要求用户输入目标账号的密码,匹配成功则认证通过,否则不通过。这套逻辑并不复杂,开发人员开发出来便是了。

过了几天,用户提出了这样的一个需求:运维团队都属于 wheel 组,能不能让 wheel 组的用户也能不输入密码而使用 su 切换?看起来也不是什么特别困难的需求,开发人员本可以满足就是了。但是如果再过几天,运维小张考虑到安全想要 su 有短信验证码功能,而用户小王为了方便测试想要一个完全不用密码的 su。认证需求的差异化越来越明显,开发人员的工作也变得越来越困难。

这时PAM 出现了对开发人员说:“认证的事情交给我,你只要告诉我你想做用户认证就好,余下的事情由我来解决,能不能通过由我来说了算。”它又对运维人员说:“你们来我这里编写你们想要的针对 su 的认证策略吧,我将充分保证功能的灵活。”

从此su 的开发人员可以专注地为用户启动 Shell 服务,而不需要关心用户认证的细节了;用户或复杂、或简单的认证需求也都得到了满足。真是皆大欢喜。

注意事项:

  • Linux系统下的应用程序如果需要得到PAM功能的支持,需要将支持PAM功能的代码集成到了源代码之中;如果你能够得到一个应用程序的原代码,你也可以自行将支持 PAM 的功能代码加入其中。
  • 查看应用程序是否支持 PAM 验证功能,使用ldd命令进行查看动态链接库中有木有 libpam 和 libpam.misc名称;
    1
    2
    ldd `which sshd` | grep "libpam"
    libpam.so.0 => /lib64/libpam.so.0 (0x00007fa969d54000)
  • PAM 不仅仅在用户登录时才发挥作用sudo命令,su命令,passwd命令都会用到 PAM。前文中所有提及“登录”的地方都仅仅是举例,您完全可以用其他需要用户认证的服务(或者命令)去举例,从而更全面地理解 PAM。

0x01 基础配置

描述:在Linux发行版的系统中每个支持PAM验证的应用程序或者服务都一个与之对应的PAM的配置文件;
默认PAM 的各个模块路径: /lib/security/ 和 /lib64/security/以动态库文件的形式存在文件名格式一般为pam_*.so(取决于操作系统位数);
默认PAM 配置文件路径:/etc/pam.conf(在时下的发行版可能没有)或者 /etc/pam.d/单个应用;

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
ls -alh /etc/pam.d/
总用量 112K
-rw-r--r--. 1 root root 192 4月 1 12:51 chfn
-rw-r--r--. 1 root root 192 4月 1 12:51 chsh
-rw-r--r--. 1 root root 232 4月 1 11:59 config-util
-rw-r--r--. 1 root root 287 8月 9 2019 crond
lrwxrwxrwx. 1 root root 19 6月 2 14:15 fingerprint-auth -> fingerprint-auth-ac
-rw-r--r--. 1 root root 702 6月 2 14:15 fingerprint-auth-ac
-rw-r--r--. 1 root root 796 4月 1 12:51 login
-rw-r--r--. 1 root root 154 4月 1 11:59 other
-rw-r--r--. 1 root root 188 4月 1 11:57 passwd
lrwxrwxrwx. 1 root root 16 6月 2 14:15 password-auth -> password-auth-ac
-rw-r--r--. 1 root root 1.1K 6月 2 14:15 password-auth-ac
-rw-r--r--. 1 root root 155 4月 1 12:07 polkit-1
lrwxrwxrwx. 1 root root 12 6月 2 14:15 postlogin -> postlogin-ac
-rw-r--r--. 1 root root 330 6月 2 14:15 postlogin-ac
-rw-r--r--. 1 root root 681 4月 1 12:51 remote
-rw-r--r--. 1 root root 143 4月 1 12:51 runuser
-rw-r--r--. 1 root root 138 4月 1 12:51 runuser-l
lrwxrwxrwx. 1 root root 17 6月 2 14:15 smartcard-auth -> smartcard-auth-ac
-rw-r--r--. 1 root root 752 6月 2 14:15 smartcard-auth-ac
lrwxrwxrwx. 1 root root 25 6月 2 14:12 smtp -> /etc/alternatives/mta-pam
-rw-r--r--. 1 root root 76 4月 1 12:08 smtp.postfix
-rw-r--r--. 1 root root 904 8月 9 2019 sshd
-rw-r--r--. 1 root root 540 4月 1 12:51 su
-rw-r--r--. 1 root root 200 4月 1 12:37 sudo
-rw-r--r--. 1 root root 178 4月 1 12:37 sudo-i
-rw-r--r--. 1 root root 137 4月 1 12:51 su-l
lrwxrwxrwx. 1 root root 14 6月 2 14:15 system-auth -> system-auth-ac #Linux系统认证相关pam(默认采用)
-rw-r--r--. 1 root root 1.1K 6月 2 14:15 system-auth-ac
-rw-r--r--. 1 root root 129 5月 12 23:45 systemd-user
-rw-r--r--. 1 root root 84 10月 31 2018 vlock

  • Linux-PAM中/etc/pam.conf类型的格式如下:

    1
    服务名称  工作类别  控制模式  模块路径  模块参数
  • PAM配置文件/etc/pam.d/中使用如下所示的语法格式:

    1
    2
    3
    4
    5
    6
    工作类别  控制模式      模块路径        模块参数
    Type Control-flag Module-path Module-arguments

    #%PAM-1.0
    auth required pam_sepermit.so
    session required pam_selinux.so open env_params

其中每行代表一个独立的验证方式每个配置文件可以由多种验证规则相互叠加而成
验证时 PAM-API 会按照从上往下的方式一一读取这些验证规则,并根据其中的控制标志做出相应的动作。

PAM配置文件特殊字符说明:

  • # 表示注释
  • 每一行代表一条规则。但也可以用\ 来放在行末,来连接该行和下一行。
  • 例子的最后一行开头有一个短横线 - 意思是如果找不到这个模块,导致无法被加载时,这一事件不会被记录在日志中。这个功能适用于那些认证时非必需的、安装时可能没被安装进系统的模块。

注意事项:

  • 在进行应用或者系统相关服务的PAM配置的时候需要小心谨慎,由于规则验证有严格的上下顺序之分所以配置时候需要核验,因为一旦出错可导致系统或者功能不能正常访问;
  • 不难看出/etc/pam.conf与/etc/pam.d/类型的配置文件中的不同,文件夹形式的配置文件中只是没有了服务名称这一列服务名称已经是文件名了。


1.配置简要说明

描述:要正常配置 PAM 配置文件就应当了解配置文件方法格式中每列的所包括的内容,下面是这些列的简短说明:

Type 列
备注:主要用来指定需要验证的类型共有以下四种验证类型;

  • auth: 主要负责验证使用者身份以及用户权限授予; 例如你的验证方式有很多比如一次性密码、指纹、虹膜等等,都应该添加在 auth 下以及比如赋给用户某个组的组员身份等等。
  • account: 主要负责在用户能不能使用某服务上具有发言权,但不负责身份认证; 例如验证帐户的此操作是否已经过期,权限多大,拥有此权限的时间期限是否已经过期等等
  • password: 主要负责和密码有关的工作; 例如控制密码的使用期限,重复输入的次数,密码锁定后的解禁时限以及保存密码的加密放方式等; (等保必须要做的)
  • session: 主要负责对每个会话进行跟踪和记录,例如记录的内容包括登录的用户名及登录的时间和次数等等


Control-flag 列
备注:主要用来控制在验证过程中动作和返回结果的方式, 简单的说用于定义各个认证模块在给出各种结果时 PAM 的行为,或者调用在别的配置文件中定义的认证流程栈;

它有两种类型的表达方式关键字模式“用方括号 [] 包含的“返回值=行为”模式:

  • (1) “关键字”模式下,有以下几种控制模式:
    • required: 当使用此控制标志时,当验证失败时仍然会继续进行其下的验证过程,它会返回一个错误信息,但是由于它不会由于验证失败而停止继续验证过程,因此用户不会知道是哪个规则项验证失败;
    • requisite: 与required 的验证方式大体相似,但是只要某个规则项验证失败则立即结束整个验证过程,并返回一个错误信息。使用此关键字可以防止一些通过暴力猜解密码的攻击,但是由于它会返回信息给用户,因此它也有可能将系统的用户结构信息透露给攻击者。
    • sufficient: 只要有此控制标志的一个规则项验证成功,那么 PAM 构架将会立即终止其后所有的验证,并且不论其前面的 required 标志的项没有成功验证,它依然将被忽略然后验证通过。
    • optional: 表明对验证的成功或失败都是可有可无的,所有的都会被忽略。(通常用于 session 类型)
    • include: 将其他配置文件中的流程栈包含在当前的位置,就好像将其他配置文件中的内容复制粘贴到这里一样。
    • substack:运行其他配置文件中的流程,并将整个运行结果作为该行的结果进行输出。该模式和 include 的不同点在于认证结果的作用域:如果某个流程栈 include 了一个带 requisite 的栈,这个 requisite 失败将直接导致认证失败同时退出栈;而某个流程栈 substack 了同样的栈时,requisite 的失败只会导致这个子栈返回失败信号,母栈并不会在此退出。
  • (2) 复杂的控制标志能够让管理员可以指定在验证过程中发生某种事件时可以执行的动作, 复杂的可以使用方括号来嵌套控制标志并可在方括号中使用 value=action 的方式表达。
    • 查看PAM中可用的Value列表值:/usr/include/security/_pam_types.hsuccess、user_unknown、new_authtok_reqd、default 等等数十种
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      #其格式如下:[value1=action1 value2=action2]
      auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so

      #流程栈中很可能有多个验证规则,每条验证的返回值可能不尽相同,那么到底哪一个验证规则能作为最终的结果呢?
      ignore:在一个栈中有多个认证条目的情况下,如果标记 ignore 的返回值被命中,那么这条返回值不会对最终的认证结果产生影响。
      bad:标记 bad 的返回值被命中时,最终的认证结果注定会失败。此外,如果这条 bad 的返回值是整个栈的第一个失败项,那么整个栈的返回值一定是这个返回值,后面的认证无论结果怎样都改变不了现状了。
      die:标记 die 的返回值被命中时,马上退出栈并宣告失败。整个返回值为这个 die 的返回值。
      ok:在一个栈的运行过程中,如果 ok 前面没有返回值,或者前面的返回值为 PAM_SUCCESS,那么这个标记了 ok 的返回值将覆盖前面的返回值。但如果前面执行过的验证中有最终将导致失败的返回值,那 ok 标记的值将不会起作用。
      done:在前面没有 bad 值被命中的情况下,done 值被命中之后将马上被返回,并退出整个栈。
      N(一个自然数):功效和 ok 类似,并且会跳过接下来的 N 个验证步骤。如果 N = 0 则和 ok 完全相同。
      reset:清空之前生效的返回值,并且从下面的验证起重新开始。

PS:实际上关键字模式可以等效地用返回值=行为模式来表示,具体的对应如下:

1
2
3
4
required:  [success=ok new_authtok_reqd=ok ignore=ignore default=bad]
requisite: [success=ok new_authtok_reqd=ok ignore=ignore default=die]
sufficient:[success=done new_authtok_reqd=done default=ignore]
optional: [success=ok new_authtok_reqd=ok default=ignore]


Module-path
描述:用来为要验证的服务提供需要使用的验证模块,前我们说过引用的动态链接库处于 /lib/security//lib64/security/ 目录中;

注意事项:

  • 使用时如果模块在默认路径之中则只填写其完整的动态链接库名称,如要引用的模块不存在这两个默认的保存目录,就必需在模块的完整名称前加上完整的模块路径名/usr/lib/security/pam-test.so


Module-arguments
描述:用来为引用的模块指定特殊的选项, 模块参数用空格与模块路径相隔。该参数将只和特定模块相关,因此某个模块的文档中一定包含其参数的信息。

注意事项:

  • 如果需要在单个参数中使用空格可以将整个参数用方括号 [] 包裹起来, 当选项超过一行时用 \ 符号连接下一行;


2.常用模块说明

描述:要想掌握PAM的使用,就必须了解常用的PAM验证模块的作用,毕竟PAM 的具体验证功能都是由这些可插入的验证模块来完成的。
每个PAM验证模块的使用对象总是与PAM验证类型是相对应即(白话:动态链接库名称包含Type关键字相关关联的名称或者应用相关关键字)

1
2
3
4
5
6
$ls /usr/lib64/security/
pam_access.so pam_debug.so pam_faildelay.so pam_group.so pam_listfile.so pam_motd.so pam_pwhistory.so pam_selinux_permit.so pam_succeed_if.so pam_tty_audit.so pam_unix_session.so pam_xauth.so
pam_cap.so pam_deny.so pam_faillock.so pam_issue.so pam_localuser.so pam_namespace.so pam_pwquality.so pam_selinux.so pam_systemd.so pam_umask.so pam_unix.so
pam_chroot.so pam_echo.so pam_filter pam_keyinit.so pam_loginuid.so pam_nologin.so pam_rhosts.so pam_sepermit.so pam_tally2.so pam_unix_acct.so pam_userdb.so
pam_console.so pam_env.so pam_filter.so pam_lastlog.so pam_mail.so pam_permit.so pam_rootok.so pam_shells.so pam_time.so pam_unix_auth.so pam_warn.so
pam_cracklib.so pam_exec.so pam_ftp.so pam_limits.so pam_mkhomedir.so pam_postgresok.so pam_securetty.so pam_stress.so pam_timestamp.so pam_unix_passwd.so pam_wheel.so


(1) pam_access|登陆访问限制模块

描述:它主要用于对访问进入管理,提供基于登录名、主机名或域名、公网 IP 地址或网络号,以及非网络登录时的 tty 名称的访问控制。
该验证模块一般与account 验证(Type)类型一同使用, 它主要是根据 /etc/security/access.conf 配置文件中的内容,来进行相应的验证工作的;

配置文件说明:

1
2
3
4
5
cat /etc/security/access.conf
## 每一行都由如下三个字段构成 permission:users:origins
permission (权限)字段可以用 + 即表示允许访问, - 禁止访问来表示相应的权限。
users/groups(用户或组)字段可以是一个或几个登录名、组名及 ALL (表示任何人)的一个清单。
origins (来源)字段可以是非网络登录时的 tty 名称、主机名、域名(以.开始)、主机地址、网络号(以.结束)、带有子网掩码的公网 IP 地址,以及 ALL 表示任何主机和 LOCAL 只要不包含.的所有字符)

基础示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 1.Disallow non-root logins on tty1
-:ALL EXCEPT root:tty1 #EXCEPT 表示排除 PS补充网络登陆`pts/0`

# 2.除了少数帐户,不允许控制台登录所有帐户
-:ALL EXCEPT wheel shutdown sync:LOCAL

# 3.有些ws相关帐户不允许从任何地方登录:
-:wsbscaro wsbsecr wscosor wstaiwde:ALL

# 4.用户“根”应该被允许从ip地址的主机访问。
+:root:192.168.200.1 192.168.200.4 192.168.200.9
+:root:192.168.201. #The same is 192.168.201.0/24 or 192.168.201.0/255.255.255.0

# 5.用户“根”应该能够从域访问。也使用字符串匹配。
+:root:.foo.bar.org

# 6.User "john" should get access from ipv6 net/mask
+:john:2001:4ca0:0:101::/64

注意事项:

  • 1.如果 access.conf 文件不在缺省的 /etc/security/ 目录,你可以在其后使用 accessfile 参数指定自定义配置文件的绝对路径。


(2) pam_cracklib|密码策略验证模块

描述:该模块通常与password验证类型一起使用,通过插入 password 堆栈为特殊的应用提供可插入式密码强度性检测,它是PAM 配置接口的基本模块。
它的工作方式就是先提示用户输入密码,然后使用一个系统字典和一套规则来检测输入的密码是否不能满足强壮性要求。

密码的强度检测分二次进行:

  • 1.第一次只是检测密码是否是提供的对比字典中的一部分
  • 2.如果检测结果是否定的,那么就会提供一些附加的检测来进一步检测其强度,(例如检测新密码中的字符占旧密码字符的比例,密码的长度,所用字符大小写状况,以及是否使用了特殊字符等等。)

pam_cracklib选项:

  • debug:此选项表示将模块信息写入系统日志;
  • type=xxx :此选项用来修改缺省的密码提示文本;(默认是 "New UNIX password: " and "Retype UNIX password: ")
  • retry=N: 定义用户在重试输入多少次密码后,返回一个错误信息,然后不准继续输入;(缺省一次)
  • difok=N: 此选项用来定义新密码中必须有几个字符要与旧密码不同,缺省是1/2以上的字符与旧密码不同时就OK;
  • maxlen=N:此选项用来设置新密码的最大长度
  • minlen=N:此选项用来设置新密码的最小长度。
  • dcredit=N:此选项用来设定新密码中可以包含数字的最大数目。
  • ucredit=N:此选项用来设定新密码中可以包含的大写字母的最大数目。
  • lcredit=N:此选项用来设定新密码中可以包含的小写字母的最大数目。
  • ocredit=N:此选项用来设定新密码中可以包含的特殊字符的最大数目。
  • minclass=N:此选项用来规定新密码中的字符类别的最小数目,字符一般有四种类别:数字、大写字母、小写字母,以及特殊字符。
  • dictpath=/path/to/dict: 指定 cracklib 目录路径。
  • use_authtok:在某个与密码相关的验证模块后使用此选项,例如 pam_unix.so 验证模块,可以强迫此模块不提示输入密码而使用上面设置的另一种方式;


(3) pam_limit|资源服务限制模块

描述:该模块通常与session验证类别一同使用,它主要用来限制用户在会话过程中对系统资源的使用,即使 UID=0 的用户也受它的限制;
默认独立的配置文件: /etc/security/limits.conf
模块参数选项: conf选项指定自定义配置文件即sudo:session required pam_limits.so conf=/etc/custom_limits.conf

配置文件格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
## <domain>        <type>  <item>  <value>
- <domain> : 可以是用户名、采用@group 语法的组名,还可以用通配符 * 来表示任何用户, 以及使用 “%” 通配符来只限制 maxlogins ,并可以采用 %group 的语法格式。

- <type> :
- soft : 用来设置对系统资源的软限制,它允许用户所使用的系统资源可以在设定的硬限制值的规定范围来上下浮动
- hard : 用来设置对系统资源的硬限制,这些硬限制由超级用户设置,并由系统内核来执行。(`普通用户对系统资源的使用率不能超过设置的硬限制设定值`)
- "-" : 表示无限制系统资源;

- <item> <value> : 两者总是成对使用的,"Item"表示某类具体的系统资源,而"Value"就是"Item"的值;
* as # 地址空间限制( KB )
* core # 核心文件的大小 (KB)
* data # 最大的数据包大小 (KB)
* fsize # 最大的文件大小 (KB)
* memlock # 最大可用的内存空间 (KB)
* rss # 最大的可驻留空间 (KB)
* stack # 最大的堆栈空间 (KB)
* cpu # 最大的 CPU 占用时间( minutes )
* nproc # 最大允许运行的进程数量
* maxlogins # 用户可以登录到系统的最多次数, UID=0 的用户除外
* priority # 优先运行的用户进程(负值越高的进程优先)
* sigpending # 最大数量的等待信号( Linux2.6 及以上内核)
* msqqueue # POSIX 信息队列的最大可使用的内存( bytes )( Linux2.6 及以上内核)
* nofile # 最大可以打开的文件数量
* locks # 最大可锁定文件的数目( Linux2.4 及以上内核的系统)

注意事项:

  • 1.上面item项目中是一些对系统资源使用情况非常有用的但它仅仅是一部分,可能随着内核的升级会加入某些新的item,你可以通过查看其帮助文档来了解;
  • 2.十分注意用户的限制优先级要高于组的限制,如果你为一个组设置了某种系统资源限制,但是其中的某个用户设置了另一级别的系统资源限制,那么系统将会优先按用户级别的限制处理;


(4) pam_time|日期时间终端限制模块

描述:该模块通常与 account 验证类型一起使用,它并不对用户提供验证服务,而是用来限制用户在指定的日期、时间及终端线路上对系统或特定应用程序进行访问
默认配置文件路径:/etc/security/time.conf
配置文件语法格式:

1
2
3
4
5
6
7
8
9
#最初主要基于shadow package (shadow-960129)。
#基础语法: services;ttys;users;times
- services 字段:表示应用 PAM 功能的服务名称。
- ttys 字段:应用此规则的终端名,可以*号表示任何终端,!表示非。
- users 字段:应用此规则的用户名单或网络组名,可以 “*” 号表示任何用户,!表示非。
- times 字段:指定时间,通常使用日期 / 时间范围的格式来表示
- 日期: #Mo 、 Tu 、 We 、 Th 、 Fr 、 Sa 、 Su 、 Wk 、 Wd 、 Al , Mo 到 Su 分别指从星期一到星期天(Wk 指每一天/Wd 指周末/ Al 也指每一天),
- 时间:#采用 24 小时制,即 HHMM (时分)的形式
- 日期 / 时间范围前可有 ! 表表除此以外的所有日期 / 时间 , 还可以用 - 连接指定的时间范围;

基础实例:

1
2
3
4
5
6
7
8
#示例1. MoMo 表示任何一天都没有,Al1800-0800 就是指每天下午 6 点整到第二天的早晨 8 点整。
xsh;tty*;root;!MoMo1800-0600

#实例2.用户'root'被拒绝xsh访问终端,在周末和星期1
xsh;ttyp*;root;!WdMo0000-2400

#示例3.在tty*(任何ttyXXX设备)上运行用户you和me一直被拒绝服务
blank;tty* & !ttyp*;you|me;!Al0000-2400


(5) pam_listfile|文件服务访问验证模块

描述:该验证模块通常与 auth 验证类型一起使用,此模块提供根据某个指定的文件来允许或禁止用户访问某个应用程序或服务的功能,这些被指定的文件必需事先存在,然后通过 file 参数来指定该文件。
该模块可以根据用户名、 tty 、 rhost 、 ruser 、用户组、使用的 shell 来对用户进行访问控制。

模块选项:

1
2
3
4
5
* item=[tty|user|rhost|ruser|group|shell] : 设置访问控制的对象类型。
* apply=[user|@group] :用指定使用非用户和组类别时,这些规则所适用的对象。当 item=[user|ruser|group] 时该选项没有任何意义,只有当 item=[tty|rhost|shell] 时才有意思。
* sense=allow|deny : 用来指定当在保存 "item" 对象的文件中找不到 item 指定的对象时的动作方式,如果在文件中找不到相应的对象则执行相反的动作。
* onerr=succeed|fail : 用来指定当某类事件(如无法打开配置文件)发生时的返回值。
* file=filename : 指定保存有 "item" 对象的文件位置。

基础实例:

1
2
#示例1.auth验证类型依赖于pam_listfile.so(如有错误继续执行),访问对象为user组且与ftpusers文件中的用户一一对应否则阻止,当产生某类事件时候返回succeed;
vsftpd:auth required pam_listfile.so item=user sense=deny file=/etc/vsftpd/ftpusers onerr=succeed


(6) pam_unix|认证类型验证模块

描述:该模块提供基于 /etc/passwd 和 /etc/shadow 文件的类 UNIX 风格的认证,它适用所有的验证类型,包括: auth 、 account 、 password 、 session

模块选项:

1
2
3
4
5
6
7
8
9
10
11
12
13
- debug: 将调试信息写入系统日志,当pam_unix 验证模块与所有验证类别使用时都有效。
- audit: 提供比 debug 更多诊断调试,它只有当与auth 、 account 及 password 验证类型使用时有效。
- nullok: 默认情况下如果密码为空那么就不允许用户访某项服务,而使用此项后将则覆盖这个默认动作。它只有当与 auth 、和 password 验证类型使用时有效。
- nodelay :当用户验证失败后,系统在给出错误信息时会有一个延迟,默认为 2 秒钟。当使用此选项后,将取消这个延迟。它只有当与 auth 验证类型使用时有效
- use_first_pass :当与 auth 验证类型一起使用时,使用该选项将在提示用户输入密码前,直接使用以往的密码验证方式来对用户进行验证。而当与 password 验证类型一起使用时,该选项主要用来防止用户新设定的密码与前面 password 提供的密码相同。
- try_first_pass :当与 auth 验证类型一起使用时,使用该选项将在提示用户输入密码前,尝试使用以往的密码验证方式来对用户进行验证。而当与 password 验证类型一起使用时,该选项主要用来防止用户新设定的密码与以前的旧密码相同
- use_authok :当用户修改时使用此选项强制用户使用前面堆叠验证模块提供的密码,例如由 pam_cracklib 验证模块提供的新密码。当与 password 验证类型一起使用时有效。
- md5 : 采用 md5 对用户密码进行加密,当与 password 验证类型一起使用时有效。
- shadow : 使用用 shadow 密码,当与 password 验证类型一起使用时有效。
- sha256 : 使用此选项,当下次修改密码时将用 SHA256 算法加密,如果 SHA256 的 libcrypt 不存在,就会重新使用 MD5 加密密码。
- Sha512 : 与此选项相同,只是加密强大不同而已。当与 password 验证类型一起使用时有效。
- rounds=n : 用来指定使用 SHA256 和 SHA512 算法加密密码时重复哈希算法的次数。当与 password 验证类型一起使用时有效。
- remember=n : 使用此选项将会将 n 个使用过的旧密码,以 MD5 的方式加密后保存到 /etc/security/opasswd 文件中。当与 password 验证类型一起使用时有效。

基础实例:

1
2
3
4
5
6
#登陆时尝试使用以往的密码验证方式来对用户进行验证,可以输入空密码
system-auth-ac:auth sufficient pam_unix.so nullok try_first_pass
system-auth-ac:account required pam_unix.so
#使用512加密方式的 shadow 密码,并用户修改时使用此选项强制用户使用前面堆叠验证模块提供的密码
system-auth-ac:password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok
system-auth-ac:session required pam_unix.so

注意事项:

  • 1.与 auth 验证类型一起使用时,此模块可以使用的选项有 debug 、 audit 、 use_first_pass 、 try_first_pass 、 nullok 和 nodelay ,主要功能是验证用户密码的有效性,在缺省情况下(即不带任何参数时),该模块的主要功能是禁止密码为空的用户提供服务;
  • 2.在作为 account 类型使用时,此时该模块可识别的参数有 debug 、 audit ,该模块主要执行建立用户帐号和密码状态的任务,然后执行提示用户修改密码,用户采用新密码后才提供服务之类的任务;
  • 3.在作为 password 类型使用时,此时该模块可识别的参数有 debug 、 audit 、 nullok; 、 not_set_pass 、 use_authtok 、 try_first_pass 、 use_first_pass 、 md5 、 bigcrypt 、 shadow 、 nis 、remember ,该模块完成让用户更改密码的任务;
  • 4.在作为 session 类型使用时,此时该模块没有可识别的参数,该模块仅仅完成记录用户名和服务名到日志文件的工作。


(7) pam_deny|配置访问验证模块

描述:该验证模块可以用来禁止所有的访问,当你设置 PAM 配置文件时,为了安全,在开始的行可以使用它来禁止所有的访问,以减少错误配置引起的安全风险。
而 pam_permit 验证模块却总是允许所有的访问,你要谨慎的使用此验证模块。它们都适用于所有的验证类型。


(8) pam_rootok|验证模块

描述:该验证模块允许 /etc/pam.d/su 中的用户不需要任何验证就可以登录系统。因此你应当小心设置 /etc/pam.d/su 文件,并且在使用时要与 pam_wheel 验证模块一同使用,以保证 root 权限只允许在 pam_wheel 的限制中进行。它只适用于 auth 验证类型。

1
2
3
4
5
6
7
$ cat /etc/pam.d/su
#%PAM-1.0
auth sufficient pam_rootok.so
# Uncomment the following line to implicitly trust users in the "wheel" group.
#auth sufficient pam_wheel.so trust use_uid
# Uncomment the following line to require a user to be in the "wheel" group.
#auth required pam_wheel.so use_uid


(9) pam_security|验证模块

描述:该验证模块只对 root 用户有影响。当 root 用户登录时, pam_security 验证模块会参考 /etc/securetty 目录中的控制终端列表,来保证 root 用户不会从不安全的终端登录,它一般与 auth 验证类型一现使用。

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
$ cat /etc/securetty
console
vc/1
vc/2
vc/3
vc/4
vc/5
vc/6
vc/7
vc/8
vc/9
vc/10
vc/11
tty1
tty2
tty3
tty4
tty5
tty6
tty7
tty8
tty9
tty10
tty11
ttyS0
ttysclp0
sclp_line0
3270/tty1
hvc0
hvc1
hvc2
hvc3
hvc4
hvc5
hvc6
hvc7
hvsi0
hvsi1
hvsi2
xvc0


(10) pam_nologin|验证模块

描述:该验证模块如果 /etc/nologin 文件存在,此模块将禁止所有的登录。它一般与 auth 和 account 验证类型一同使用。


(11) pam_echo|验证模块

描述:该验证模块用来给用户显示通过 file 选项指定的文件中的内容,它适用于所有的验证类型。


(12) pam_motd 验证模块

允许将 /etc/motd 文件中的内容显示给用户,它只适用于 session 验证类型。


(13) pam_lastlog|验证模块

描述:显示用户上次登录的日期和时间,它主要通过读取 /var/log/lastlog 文件来显示。它只适用与 session 验证类型。


(14) pam_warn|验证模块

描述:将刚登录的信息记录到系统日志当中,它一般与 auth 和 password 验证类型一同使用。


(15) pam_wheel|验证模块

描述:当使用此验证模块后,只有加入到了一个 wheel group 中的的根用户,并且提交的密码有效,才能访问指定的服务或系统。将它与 pam_rootok 一同使用能增加对根用户的限制。它只适用于 auth 和 account 验证类型。


(16) pam_passwdqc|密码策略验证模块

描述:该模块与pam_cracklib差不多,主要用来设置Linux用户密码的复杂度;

模块选项说明:

1
2
3
4
5
6
7
8
9
10
11
12
* mix: 设置口令字最小长度,默认值是 mix=disabled 。
* max: 设置口令字的最大长度,默认值是 max=40 。
* passphrase: 设置口令短语中单词的最少个数,默认值是 passphrase=3 ,如果为 0 则禁用口令短语。
* atch: 设置密码串的常见程序,默认值是 match=4 。
* similar: 设置当我们重设口令时,重新设置的新口令能否与旧口令相似,它可以是permit 允许相似或 deny 不允许相似。
* random: 设置随机生成口令字的默认长度。默认值是 random=42 ,设为 0 则禁止该功能。
* retry: 设置用户输入口令字时允许重试的次数,默认值是 retry=3
* enforce: 设置约束范围
- enforce=none 表示只警告弱口令字,但不禁止它们使用;
- enforce=users 将对系统上的全体非根用户实行这一限制;
- enforce=everyone 将对包括根用户在内的全体用户实行这一限制。
* non-unix: 它告诉这个模块不要使用传统的 getpwnam 函数调用获得用户信息,

PS:PAM 管理员指南来得到它们的详细说明。


0x02 PAM应用

描述:在说到PAM实例应用的使用,我们来复用一哈/etc/passwd文件中用户相关信息;

1
2
3
4
5
6
7
$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
#用户名称:x:用户id:用户组id:用户描述:用户家目录:用户将登录shell类型

$ cat /etc/shadow
web:$6$s15TWGyS4h9vSto8$Te5j92jO6FLTRbI5CE2f0ECM66rPl4yJQm9GMPpYNrTGBtR2WbkpZJxfJEdw.ieSat5eWRiI0jQzwk9cbuO2a.::0:99999:7:::
#用户名称:用户密码(sha512)无密码*:上次修改密码时间(天为单位):限制多少天才可以更改密码(0表示不限制):限制密码使用多长时间后必须设置修改(9999表示无限制):密码到期前7天提醒用户:账户失效时间:到此时间自动取消:系统保留


1.用户密码复杂度

描述:Linux 用户密码的有效期是否可以修改密码可以通过 login.defs 文件控制,注意对 login.defs 文件修只影响后续建立的用户,如果要改变以前建立的用户的有效期等可以使用 chage 命令。

Linux 用户密码的复杂度可以通过 pam_cracklibpam_passwdqc 模块控制 , 两者不能同时使用个人感觉 pam_passwdqc 更好用。

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
cat /etc/login.defs
# 依赖参见 /etc/pam.d/system-auth
# *REQUIRED*
# Directory where mailboxes reside, _or_ name of file, relative to the home directory. If you _do_ define both, MAIL_DIR takes precedence.
# QMAIL_DIR is for Qmail
#QMAIL_DIR Maildir
MAIL_DIR /var/spool/mail
#MAIL_FILE .mail

# Password aging controls: 密码策略设置
PASS_MAX_DAYS 99999 # 密码的最大有效期 99999永久有期
PASS_MIN_DAYS 0
PASS_MIN_LEN 5
PASS_WARN_AGE 7 #失效前多少天提醒

# Min/max values for automatic uid selection in useradd : 用户ID起始值
UID_MIN 1000
UID_MAX 60000
# System accounts : 系统用户ID起始值
SYS_UID_MIN 201
SYS_UID_MAX 999

# Min/max values for automatic gid selection in groupadd : 组用户起始值
GID_MIN 1000
GID_MAX 60000
# System accounts : 系统组用户起始值
SYS_GID_MIN 201
SYS_GID_MAX 999

# If defined, this command is run when removing a user.
# It should remove any at/cron/print jobs etc. owned by
# the user to be removed (passed as the first argument).
#USERDEL_CMD /usr/sbin/userdel_local

# If useradd should create home directories for users by default
# On RH systems, we do. This option is overridden with the -m flag on
# useradd command line.
CREATE_HOME yes

# The permission mask is initialized to this value. If not specified, the permission mask will be initialized to 022.
# 权限掩码初始化,否则默认为022
UMASK 077

# This enables userdel to remove user groups if no members exist. : 允许userdel在不存在成员的情况下删除用户组。
USERGROUPS_ENAB yes

# Use SHA512 to encrypt password : 加密方式
ENCRYPT_METHOD SHA512

密码复杂度通过 /etc/pam.d/system-auth 实施:

1
2
3
4
5
6
7
8
# 1.要使用 pam_cracklib 将注释去掉 , 把 pam_passwdqc.so 注释掉即可;
#password requisite /lib/security/$ISA/pam_cracklib.so retry=3 difok=1 #新密码至少有一位与原来的不同;
password requisite /lib/security/$ISA/pam_passwdqc.so min=disabled,24,12,8,7 passphrase=3
password sufficient /lib/security/$ISA/pam_unix.so nullok use_authtok md5 shadow

# 2.基础使用说明
password required pam_cracklib.so retry=3 minlen=12 difok=4 #密码最小长度12且新旧密码四位不同;
password required pam_unix.so sha512 remember=12 use_authtok #记住12次密码不允许用户重复使用旧的密码

注意事项:

  • 1.第一步是建立一个空文件用来存储旧密码 /etc/security/opasswd ,如果你没有建立文件却使用了历史密码记录功能的话,所有的密码更新都会失败因为 pam_unix 模块会报错。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #1.建立和赋值密码记录文件
    if [[ ! -f "/etc/security/opasswd" || "$(ls -l /etc/security/opasswd | egrep -c '\-rw\-\-\-\-\-\-\-')" != "1" ]];then
    # 手动创建/etc/security/opasswd,解决首次登录修改密码时提示"passwd: Authentication token manipulation error"
    mv /etc/security/opasswd /etc/security/opasswd.old > /dev/null 2>&1
    touch /etc/security/opasswd
    chown root:root /etc/security/opasswd
    chmod +600 /etc/security/opasswd
    fi

    #2.opasswd 文件内容格式如下:
    hal:1000::,,..., #以 : 分割,第一列是用户名,第二列是用户 ID ,第三列是目前记录了该用户多少个旧密码, hashN 是每次密码的 sha512 值, opasswd 在某些系统安装 PAM 模块时会自动建立
  • 2.检查用户设置的密码是不是违反系统内部的密码字典,不同的发行版密码字典存放地址是不一样的,在Debian:/var/cache/cracklibCentOS:/usr/share/cracklib 目录下,而且每天晚上 update-cracklib 脚本会自动的 rebuild 密码字典。
  • 3.在密码管理方面 one time password(OTP) 也很有效果,动态密码管理,有兴趣的同学可以研究一下。

2.访问锁定

描述:下面主要正对于ssh多次登录失败锁定用户;

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
1 、修改配置文件
# vi /etc/pam.d/system-auth
auth required pam_tally.so deny=3 #(增加deny=N 为登录失败 N 次后锁定用户)
auth required pam_tally2.so deny=3 unlock_time=5 even_deny_root root_unlock_time=10

2 、在客户端测试
# ssh [email protected] ( user 为服务器端的用户 ,192.168.1.1 为主机 IP 地址)

3 、3 次后再次测试并用正确密码登录会发现仍不能登录
4 、解除锁定方法
#在服务器端以 root 用户登录执行命令:
方式1: pam_tally.so
# faillog –a //// 查看用户登录错误次数
#如果超过三次的话,用户不能登录并且此后登录用户错误登录次数还是会增加。
#在登录错误次数不满三次时,登录成功后,则这个用户登录错误值将清零,退出后重新 ssh 登录将采用新的计数。
# faillog -u user –r //// 清空指定用户 user 的错误登录次数
# faillog –r //// 清空所有用户错误登录次数

#方式2: pam_tally2.so
# 使用pam_tally2命令来查看用户登录失败的信息
pam_tally2 -u test
# Login Failures Latest failure From
# test 1 06/20/17 14:18:19 192.168.56.1
# 也可用来解锁用户
pam_tally2 -r -u test