本文为在前辈的文章基础之上学习总的PAM认证机制。
Linux提供的安全机制主要有:身份标识与鉴别、文件访问控制、特权管理、安全审计、IPC资源的访问控制。本文为身份标识与鉴别其中的部分。
0x01:PAM简介
PAM 的全称为“可插拔认证模块(Pluggable Authentication Modules)”。设计的初衷是将不同的底层认证机制集中到一个高层次的API中,从而省去开发人员自己去设计和实现各种繁杂的认证机制的麻烦。如果没有 PAM ,认证功能只能写在各个应用程序中,一旦要修改某个认证方法,开发人员可能不得不重写程序,然后重新编译程序并安装;有了 PAM ,认证的工作都交给 PAM ,程序主体便可以不再关注认证问题了:“ PAM 允许你进来,那你就进来吧。”
可插入身份认证模块,即为PAM机制。当用户在登录Linux时,首先要通过系统的PAM验证。PAM机制可以用来动态地改变身份验证的方法和要求,允许身份认证模块按需要被加载到内核中,模块在加入后即可用于对用户进行身份认证,而不需要重新编译其它公用程序。PAM体系结构的模块化设计及其定义的良好接口,使得无需改变或者干扰任何现有的登录服务就可以集成范围广泛的认证和授权机制,因此,近年来,对PAM的底层鉴别模块的扩展广泛应用于增强Linux操作系统的安全性。使本地系统管理员可以随意选择程序的认证方式。换句话说,不用(重新编写和)重新编译一个包含PAM功能的应用程序,就可以改变它使用的认证机制。这种方式下,就算升级本地认证机制,也不用修改程序。
PAM使用配置文件/etc/pam.conf(或/etc/pam.d/下的文件),来管理对程序的认证方式.应用程序,调用相应的配置文件,从而调用本地的认证模块.模块放置在/lib/security下,以加载动态库的形式进行调用。像我们使用su命令时,系统会提示你输入root用户的密码.这就是su命令通过调用PAM模块实现的。
0x02:PAM配置文件
PAM 的各个模块一般存放在 /lib/security/ 或 /lib64/security/中,以动态库文件的形式存在(可参阅 dlopen(3)),文件名格式一般为 pam_*.so。PAM 的配置文件可以是 /etc/pam.conf 这一个文件,也可以是 /etc/pam.d/ 文件夹内的多个文件。如果 /etc/pam.d/ 这个文件夹存在,Linux-PAM 将自动忽略 /etc/pam.conf。
/etc/pam.conf 类型的格式如下:
服务名称 | 工作类别 | 控制模式 | 模块路径 | 模块参数 |
---|
/etc/pam.d/ 类型的配置文件通常以每一个使用 PAM 的程序的名称来命令。比如 /etc/pam.d/su,/etc/pam.d/login 等等。还有些配置文件比较通用,经常被别的配置文件引用,也放在这个文件夹下,比如 /etc/pam.d/system-auth。这些文件的格式都保持一致:
工作类别 | 控制模式 | 模块路径 | 模块参数 |
---|
不难看出,文件夹形式的配置文件中只是没有了服务名称这一列:服务名称已经是文件名了。由于很难在时下的发行版本中找到使用 /etc/pam.conf 这一独立文件作为 PAM 配置的例子,此处仅就 /etc/pam.d/ 格式举例。以login文件为例。
- #表示注释。
- 每一行代表一条规则。但也可以用 \ 来放在行末,来连接该行和下一行
-
例子的最后一行开头有一个短横线 -,意思是如果找不到这个模块,导致无法被加载时,这一事件不会被记录在日志中。这个功能适用于那些认证时非必需的、安装时可能没被安装进系统的模块。
第一列:模块类型
它们是:认证管理(auth),账号管理(account),会话管理(session)和密码(password)管理,一个类型可能有多行,它们按顺序依次由PAM模块调用.
管理方式 | 说明 | 通俗的说 |
---|---|---|
auth | 用来对用户的身份进行识别.如:提示用户输入密码,或判断用户是否为root等. | 在登录系统时,如果你连 account 这个条件都没满足的话,即便有密码也还是进不去系统的 |
account | 对帐号的各项属性进行检查.如:是否允许登录,是否达到最大用户数,或是root用户是否允许在这个终端登录等. | 决定用户能不能使用某服务,但不负责身份认证 |
session | 这个模块用来定义用户登录前的,及用户退出后所要进行的操作.如:登录连接信息,用户数据的打开与关闭,挂载文件系统等. | 用户登录之前要将用户家目录准备好,或者在用户登录之后输出 motd ,或者提供环境变量等。 |
password | 主要负责和密码有关的工作 | 使用用户信息来更新.如:修改用户密码. 设置保存密码使用哪种加密方式,但这里的密码不局限于/etc/passwd,有关token的管理都在这设置 |
第二列:控制标记
用于定义各个认证模块在给出各种结果时PAM的行为,或者调用在别的配置文件中的认证流程栈,该列有两种形式,一种是比较常见的“关键字”模式,另一种是用方括号【】包含的“返回值=行为”模式。
关键字模式下,有以下几种控制模式:
控制标记 | 说明 |
---|---|
required | 如果本条目没有被满足,那最终本次认证一定失败,但认证过程不因此打断。整个栈运行完毕之后才会返回(已经注定了的)“认证失败”信号。 |
requisite | 如果本条目没有被满足,那本次认证一定失败,而且整个栈立即中止并返回错误信号 |
sufficient | 如果本条目的条件被满足,且本条目之前没有任何required条目失败,则立即返回“认证成功”信号;如果对本条目的验证失败,不对结果造成影响 |
optional | 该条目仅在整个栈中只有这一个条目时才有决定性作用,否则无论该条验证成功与否都和最终结果无关 |
include | 将其他配置文件中的流程栈包含在当前的位置,就好像将其他配置文件中的内容复制粘贴到这里一样 |
substack | 运行其他配置文件中的流程,并将整个运行结果作为该行的结果进行输出。该模式和 include 的不同点在于认证结果的作用域:如果某个流程栈 include 了一个带 requisite 的栈,这个 requisite 失败将直接导致认证失败,同时退出栈;而某个流程栈 substack 了同样的栈时,requisite 的失败只会导致这个子栈返回失败信号,母栈并不会在此退出。 |
“返回值=行为”模式其格式如下:
[value1=action1 value2=action2 ...]
其中,valueN 的值是各个认证模块执行之后的返回值。有 success、user_unknown、new_authtok_reqd、default 等等数十种。其中,default 代表其他所有没有明确说明的返回值。返回值结果清单可以在 /usr/include/security/_pam_types.h 中找到。
流程栈中很可能有多个验证规则,每条验证的返回值可能不尽相同,那么到底哪一个验证规则能作为最终的结果呢?这就需要 actionN 的值来决定了。actionN 的值有以下几种:
action值 | 说明 |
---|---|
ignore | 在一个栈中有多个认证条目的情况下,如果标记 ignore 的返回值被命中,那么这条返回值不会对最终的认证结果产生影响 |
bad | 标记 bad 的返回值被命中时,最终的认证结果注定会失败。此外,如果这条 bad 的返回值是整个栈的第一个失败项,那么整个栈的返回值一定是这个返回值,后面的认证无论结果怎样都改变不了现状了 |
die | 标记 die 的返回值被命中时,马上退出栈并宣告失败。整个返回值为这个 die 的返回值 |
ok | 在一个栈的运行过程中,如果 ok 前面没有返回值,或者前面的返回值为 PAM_SUCCESS,那么这个标记了 ok 的返回值将覆盖前面的返回值。但如果前面执行过的验证中有最终将导致失败的返回值,那 ok 标记的值将不会起作用 |
done | 在前面没有 bad 值被命中的情况下,done 值被命中之后将马上被返回,并退出整个栈。 |
N(一个自然数) | 功效和 ok 类似,并且会跳过接下来的 N 个验证步骤。如果 N = 0 则和 ok 完全相同 |
reset | 清空之前生效的返回值,并且从下面的验证起重新开始 |
实际上,“关键字”模式可以等效地用“返回值=行为”模式来表示。具体的对应如下:
- 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]不知道做安全的小伙伴们是否还记得linux安全基线加固里的限制登录错误次数的配置?
编辑系统/etc/pam.d/system-auth 文件,在 auth 字段所在的那一部分策 略下面添加如下策略参数:
auth required pam_tally2.so onerr=fail deny=3 unlock_time=40 even_deny_root root_unlock_time=30
以上策略表示:普通帐户和 root 的帐户登录连续 3 次失败,就统一锁定 40 秒, 40 秒后可以解锁。如果不想限制 root 帐户,可以把 even_deny_root root_unlock_time
0x03常用PAM模块
0x04PAM实验
实验1:验证 required 和 requisite 的区别
在linux系统中,/etc/pam.d/system-auth 是一个通用的配置文件,su 等命令把它作为验证过程中的一个子栈。因此,修改该文件便相当于修改了 su 等命令的验证配置。system-auth 文件中 auth 工作组的内容如下:
这里我们重点关注第二行和第五行。第二行中的 pam_unix.so 会询问用户名和密码,并和 /etc/passwd 以及 /etc/shadow 做对比;第五行 pam_deny.so 会无条件地返回 err 从而导致认证失败。我们为了演示,将第五行剪切,挪至第一行和第二行之间。
根据之前介绍过的内容可知,当认证流程走到第二行时,由于 pam_deny.so 返回失败结果,且控制模式为 required,因此整个流程栈走到第二行的时候已经注定失败了。但由于 required 不会马上使流程终止,因此这个流程还会走下去。我们来尝试一下,用 su 命令从普通用户切换到 root。输入了正确的密码,依然未能通过验证。失败的结果在提示输入密码之前就已经注定了。
现在我们将第二行的 required 修改为 requisite,再尝试一次。此时的配置文件如下。
可以发现,我们这次连输入密码的机会都没有了。因为 requisite 模式直接导致了流程栈的退出。
来源:51CTO
作者:wt7315
链接:https://blog.51cto.com/wt7315/2139342