简介
PAM(Pluggable Authentication Modules):可插拔式认证模块,它是一种高效且灵活便利的用户级别的认证方式,同时也是 GNU/Linux 服务器普遍采用的认证方式。当然,不同的发行版在认证方式上会有些细微差异。
PAM 主要由一组共享文件(以 .so 后缀结尾的文件)和一些配置文件组成,其基于模块化设计、具有可插入功能的一种独立于应用程序之外的验证方式。最初设计的初衷就是将不同的底层认证机制集中到一个高级的 API 当中,省去开发人员自己去设计和实现各种繁杂认证机制的麻烦。
PAM 最初由 sun 公司(后来被 Oracle 公司收购)的 Vipin Samar 和 Charlie Lai 于1995年提出,并在其 Solaris 系统上实现,后来各个 UNIX 变体以及 GNU/Linux 发行版也陆续增加了对它的支持。PAM 是开源的,你可以在 这里 找到更多。
Q:为什么一定要使用 PAM?
- 如何确保系统中使用系统应用程序或服务或工具的用户一定是他本人?
- 如何给这些用户指定限制访问服务的时间段?
- 如何限制各种应用程序或服务对系统资源的使用率?
- …
试想下,如果没有 PAM,认证功能只能写在各个应用程序中,一旦要修改某个认证方法,开发人员可能不得不重写程序,然后重新编译程序并安装。有了 PAM 认证,用户的认证工作都交给 PAM ,程序主体便可以不再关注认证问题本身。
PAM 的特点:
- 给开发人员提供一套统一的API,也就是应用程序本身不再需要身份验证功能
- 灵活性高,可通过它为应用程序自由选择需要使用的验证方式
- 增加安全性
术语
围绕着 PAM 的一些术语相对混乱,可以说在前面两位老哥中都没有被正式定义,但他们确实在使用(这也导致使用一些术语时容易产生误导以及模棱两可)。于是在1999年,Andrew G.Morgan(Linux-PAM 的作者)撰写的白皮书中第一次建立了一致且明确的术语,虽然还不完美。
术语如下:
-
account(账号)
申请者向仲裁者申请的一套证书
-
applicant(申请者)
请求身份验证的用户或实体
-
arbitrator(仲裁者)
拥有验证申请者凭据所需权限以及批准或拒绝请求权限的用户或实体
-
chain(链)
为响应 PAM 请求而调用的模块序列。该链包括有关调用模块的顺序、传递给模块的参数以及如何解释结果的信息
-
client(客户端)
该应用程序负责代表申请者发起身份验证请求并从申请者那里获取必要的身份验证信息。
-
facility(能力)
PAM 提供的四个基本功能组之一 —— 身份验证、帐号管理、会话管理和身份验证令牌更新。
-
module(模块)
实现特定身份验证功能的一个或多个相关函数的集合,汇聚到单个(通常可动态加载的)二进制文件中,并由单个名称标识。
-
policy(策略)
描述如何处理特定服务的 PAM 请求的完整配置语句集。一个策略通常由四个链组成,每个链对应一个能力类型,尽管有些服务并不使用所有的四个能力类型 。
-
server(服务器)
代表仲裁者与客户端进行对话、检索身份验证信息、验证申请者的证书以及批准或拒绝请求的应用程序。
-
service(服务)
提供类似或相关功能并需要类似身份验证的一类服务器。PAM 策略是在每个服务的基础上定义的,因此声明相同服务名称的所有服务器都将遵循相同的策略。
-
session(会话)
服务器向申请者提供服务的上下文。会话管理专门负责设置和销毁此上下文。
-
token(令牌)
与帐户关联的信息块,如密码或密码短语,申请者必须提供这些信息以证明其身份。
-
transaction(事务)
从同一申请者到同一服务器的同一实例的一系列请求,从身份认证和会话建立开始,到会话销毁结束。
用示例来说明术语
假设客户端与服务器都是一样的(即登录了本地的物理终端):
Shell > whoami
alice
Shell > ls -l `which su`
Shell > su -
Password: qwerzasd
Shell > whoami
root
- 申请者是 alice
- 账号是 root
- su 进程既是客户端,也是服务器
- 令牌是 qwerzasd
- 仲裁者是 root
假设客户端与服务器都区分的(即登录了远程的虚拟终端):
Shell > whoami
eve
Shell > ssh [email protected]
[email protected]'s password:
god
Last login: Thu Oct 11 09:52:57 2024 from 192.168.0.1
- 申请者是eve
- 客户端是 eve 用户的 ssh 进程
- 账号是 bob
- 服务器是 login.example.com 主机上的 sshd 进程
- 身份验证令牌是 god
- 尽管该示例未显示仲裁者,但其实 root 才是仲裁者
示例策略
sshd auth required pam_nologin.so no_warn
sshd auth required pam_unix.so no_warn try_first_pass
sshd account required pam_login_access.so
sshd account required pam_unix.so
sshd session required pam_lastlog.so no_fail
sshd password required pam_permit.so
- 此策略适用于 sshd 服务
- auth、account、session 和 password 是 能力类型
- pam_nologin.so、pam_unix.so、 pam_login_access.so、pam_lastlog.so 和 pam_permit.so 是模块。从该示例可以看到,pam_unix.so 至少提供了 2 种能力(身份验证与账号管理)
PAM 要素
能力类型(Facilities)与原语(Primitives)
原语:由若干条指令组成的用于完成特定功能的一个过程。这些指令组合在一起形成一段程序,这段程序在执行过程中不可被分割和被打断,保证了操作的连续性和完整性。很像关系型数据库中 "事务" 的 A(原子性) 特性。
PAM API 提供了六种不同的身份验证原语,这些原语被划分为 4 种能力类型:
-
auth
身份验证。该能力涉及对申请者进行身份验证和建立账号凭证。
-
account
账号管理。该能力处理与身份验证无关的帐户可用性问题,例如基于时间或服务器工作负载的访问限制。
-
session
会话管理。此能力处理与会话建立、设置和结束相关的任务。
-
password
密码管理。此能力用于更改与账户关联的身份验证令牌信息。这对应着前面的「身份验证令牌更新」。
模块
模块是 PAM 当中一个非常核心的概念。毕竟,它是 "PAM" 当中的 "M"。PAM 模块是一段独立的程序代码,它为一种特定机制实现了一个或多个能力中的原语。
链和策略
当服务器启动 PAM 事务时,PAM 库会尝试加载在 pam_start 调用中指定的服务策略。该策略指定应如何处理身份验证请求,并在配置文件中定义。这是 PAM 中的另一个核心概念:管理员只需编辑文本文件即可调整系统安全策略。
策略由四个链组成,四个 PAM 能力类型中的每一个都有一个链。每个链是一系列配置语句,每个语句指定要调用的模块、要传递给模块的一些(可选)参数以及描述如何解释模块返回代码的 控制标志(control flag)。
请求 PAM 模块会返回以下三种状态之一:
- 成功 – 满足安全策略
- 失败 – 未满足安全策略
- 忽略 – 请求未参与到安全策略中
理解 控制标志 对于理解 PAM 配置文件至关重要。有几种不同的控制标志:
binding – 使用此控制标志,如果模块响应成功,并且先前带有 required 标志的模块都没有失败,则 PAM 会跳过其余模块并返回成功信息。如果返回失败信息,则 PAM 会记录必需的失败信息,然后继续处理栈。
除模块响应成功情况下不再检查任何其他模块以外,binding 控制标志类似于 required 控制标志。
- 无论其他模块如何响应,使用此标志的模块中的失败信息会阻止请求成功。
- 如果先前的必需模块都响应成功,则使用此标志的模块中的成功信息会使请求成功。
required – 使用此控制标志,如果模块响应成功,则 PAM 会记录必需的成功信息并继续检查后面的所有模块。如果此模块响应失败,并且此失败信息是第一个必需的失败信息,则 PAM 会保存错误消息并继续检查栈。如果此失败信息不是第一个失败信息,则 PAM 只会继续检查栈。此标志允许处理整个序列,从而不会泄露可帮助攻击者进行攻击的信息。攻击者可找出的所有信息就是请求失败。
如果某特定模块必须响应成功才能使请求成功,则应使用 required 控制标志。
- 无论其他模块如何响应,使用此标志的模块中的失败信息会阻止请求成功。
- 使用此标志的模块中的成功信息并不表示请求成功。栈中带有 required、requisite 或 binding 控制标志的其他模块必须都响应成功,请求才会成功。
requisite – 使用此控制标志,如果模块响应成功,则 PAM 会记录必需的成功信息并继续检查后面的所有模块。如果此模块响应失败,则 PAM 会记录必需的失败信息,返回第一个必需失败信息的错误消息,然后跳过任何其他检查。
除模块响应失败情况下不再检查任何其他模块以外,requisite 控制标志类似于 required 控制标志。
- 无论其他模块如何响应,使用此标志的模块中的失败信息会阻止请求成功。
- 使用此标志的模块中的成功信息并不表示请求成功。栈中带有 required、requisite 或 binding 控制标志的其他模块必须都响应成功,请求才会成功。
optional – 使用此控制标志,如果模块响应成功,则 PAM 会记录可选的成功信息并继续检查栈。如果此模块响应失败,则 PAM 会记录可选的失败信息并继续检查栈。
当栈中的成功验证足以对用户进行验证时,应使用 optional 控制标志。
- 仅当此特定服务无需成功执行时才应使用此标志。请求的成功或失败由必需的失败信息或成功信息确定。
- 如果用户需要具有与特定服务关联的权限才能完成其工作,则不应将模块标记为 optional。
sufficient – 使用此控制标志,如果模块响应成功,并且先前带有 required 标志的模块都没有失败,则 PAM 会跳过其余模块并返回成功信息。如果此模块响应失败,则 PAM 会记录可选的失败信息并继续检查栈。 除模块响应成功情况下不再检查任何其他模块以外,sufficient 控制标志类似于 optional 控制标志。
- 如果先前的 required 模块都响应成功,则使用此标志的模块中的成功信息会使请求成功。
- 如果其他模块都响应失败,则使用此标志的模块中的失败信息会导致请求失败。
这些控制标志可用下图进行表示(S 表示 Success,F 表示 Fail):
当服务器调用六个 PAM 原语 中的一个时,PAM 会检索原语所属能力类型的链,并按列出的顺序调用链中列出的每个模块,直到到达末尾。
