写点什么

Linux 可插拔认证模块的基本概念与架构

  • 2012-02-29
  • 本文字数:4485 字

    阅读完需:约 15 分钟

Linux 用户认证方法简介

当今 IT 环境中, 任何计算机系统都要充分考虑设计、使用和运行过程中的安全性。所以在目前主流操作系统的各个环节当中都增加了很多安全方面的功能和特性,而在众多的安全特性和功能中有相当多的技术是确保用户鉴别和身份认证方面的安全性的。

所谓用户鉴别,就是用户向系统以一种安全的方式提交自己的身份证明,然后由系统确认用户的身份是否属实的过程。换句话说,用户鉴别是系统的门户,每个用户进入到系统之前都必须经过鉴别这一道关。 而所谓认证安全,简而言之就是计算机系统确认了用户是经过授权的合法用户之后才能允许访问。安全认证最常用的方式是比对用户输入和预存于数据库中的密码。

不过在用户进行身份鉴别和安全认证的过程中,肯定会涉及几个核心问题。例如:

  • 如何真正实现正确鉴别用户的真实身份?
  • 在鉴别用户合法身份之后,如何确定用户可以对哪些资源进行访问?
  • 如何控制用户以何种方式来访问计算机资源?
  • 如何对用户的安全访问随时随地按需调整?

上述这些问题都是在设计鉴别和认证程序过程中需要充分考虑和精心设计的。而在 Linux 类的操作系统中,这些问题的处理实际上有一套完整的流程和机制。

在 Linux 类的操作系统中,最初用户鉴别过程就像各种 Unix 操作系统一样:系统管理员为用户建立一个帐号并为其指定一个口令,用户用此指定的口令登录之后重新设置自己的口令,这样用户就具有了一个只有它自己知道的口令或者密码。一般情况下,用户的身份信息在 Linux 系统中存放在 /etc/passwd 文件当中,这实际上是一个拥有简单格式的数据库表,通过":"作为分隔符分隔出多个字段,其中包括用户的名称、用户 ID、组 ID、用户说明、主目录和登录使用的 shell 等相关信息。而用户口令经过加密处理后存放于 /etc/shadow 文件中。也是一个格式类似的数据库表,除了用户名和经过加密之后的密码之外,还包括多个对密码有效期进行定义的字段,包括密码有效时间、密码报警时间等。

用户登录的时候,登录服务程序提示用户输入其用户名和口令,然后将口令加密并与 /etc/shadow 文件中对应帐号的加密口令进行比较,如果口令相匹配,说明用户的身份属实并允许此用户访问系统。这种思想基于只有用户自己知道它的口令,所以输入的口令是正确的话,那么系统就认定它是所声称的那个人。

在 Linux 类操作系统中,定义用户信息和密码信息的字段和格式都需要符合标准的 Linux Naming Service Switch 定义,即 NSS 定义。因此用户信息只要保证满足 NSS 规范,就可以来源于本地 passwd 和 shadow 之外的其它信息数据库和认证源。所以在此基础上还派生出一些其它认证解决方案。例如 NIS、LDAP 等,都可作为存放用户信息的数据库,而存放用户口令或者鉴别用户身份的数据库,可以采用专用于网络环境的 Kerberos 以及智能卡鉴别系统等方式。

这一整套的鉴别和认证方案貌似无懈可击,但是将这种解决方案真正应用到操作系统中的话就会发现一些问题:

第一,在操作系统上所包含的认证不仅仅只涉及到系统登录和访问,在系统外围往往提供了众多的应用程序,相当多的应用程序在访问过程中是有认证需求的。那么是否需要针对每一个应用程序都得加入认证和鉴别的功能?如果要,那么无论从程序的开发和使用管理角度来讲,工作量都将成倍增加;如果不要,则系统级的用户鉴别和安全认证与应用程序没有任何关系,意味着不管用户是否需要登录系统,但是对应用程序的访问都将缺乏最基本的安全性。

第二,如果针对每一个应用程序都开发用户鉴别和认证的功能,那么一旦发现所用的算法存在某些缺陷或想采用另一种鉴别和认证方法时,开发者或者用户都将不得不重写(修改或替换)应用程序,然后重新编译原程序。

所以,尤其是当实现鉴别功能的代码以通常方法作为应用程序一部分一起编译的时候,上述问题将十分突出。很明显,传统的身份鉴别和用户认证方式一旦整合到实际的操作系统中,在实用当中缺乏灵活性。

鉴于以上原因,Linux 操作系统的开发者和设计人员开始寻找一种更佳的替代方案:一方面,将鉴别功能从应用中独立出来,单独进行模块化的设计,实现和维护;另一方面,为这些鉴别模块建立标准的应用程序接口即 API,以便众多的应用程序能方便地使用它们提供的各种功能;同时,鉴别机制对上层用户(包括应用程序和最终用户)要求一定要是透明的,这样可以对使用者隐藏其中比较复杂的实现细节。

可插拔认证模块 PAM 的基本概念

事实上直到 1995 年的时候,SUN 的研究人员才提出了一种满足以上需求的方案,这就是可插拔认证模块(Pluggable Authentication Module–PAM)机制,并首次在其操作系统 Solaris 2.3 上部分实现。

可插拔认证模块(PAM)机制采用模块化设计和插件功能,使用户可以轻易地在应用程序中插入新的认证模块或替换原先的组件,同时不必对应用程序做任何修改,从而使软件的定制、维持和升级更加轻松。因为认证和鉴别机制与应用程序之间相对独立。所以应用程序可以通 PAM API 来方便地使用 PAM 提供的各种鉴别功能而不必了解太多的底层细节。此外 PAM 的易用性也较强,主要表现在它对上层屏蔽了鉴别和认证的具体细节,所以用户不必被迫学习各种各样的鉴别方式,也不必记住多个口令;又由于它实现了多鉴别认证机制的集成问题,所以单个程序可以轻易集成多种鉴别机制,如 Kerberos 和 Diffie - Hellman 等认证机制,但用户仍可以用同一个口令登录而且感觉不到采取了各种不同的鉴别方法。

在广大开发人员的努力下,各版本的 UNIX 系统陆续增加和提供了对 PAM 应用的支持。其中 Linux-PAM 是专门为 Linux 操作系统实现的,众多的 Linux 操作系统包括 Caldera、Debian、Turbo、Red Hat、SuSE 及它们的后续版本都提供对 PAM 的支持。而 FreeBSD 从 3.1 版本也开始支持 PAM。而且除了具体实现方法上多少有些不同外,各种版本 Unix 系统上 PAM 的框架是相同的。所以我们在这里介绍的 Linux 的 PAM 框架知识具有相当的普遍性,而且在下文介绍其框架过程中可以看到,我们并没有刻意区分 Unix PAM 与 Linux PAM 这两个技术术语。

PAM 的分层体系结构

PAM 为了实现其插件功能和易用性,采取了分层设计思想。就是让各鉴别模块从应用程序中独立出来,然后通过 PAM API 作为两者联系的纽带,这样应用程序就可以根据需要灵活地在其中"插入"所需要的鉴别功能模块,从而真正实现了在认证和鉴别基础上的随需应变。实际上,这一思路也非常符合软件设计中的"高内聚,低耦合"这一重要思想。

PAM 的体系如下简图所示:

从上面的结构图可以看出,PAM 的 API 起着承上启下的作用,它是应用程序和认证鉴别模块之间联系的纽带和桥梁:当应用程序调用 PAM API 时,应用接口层按照 PAM 配置文件的定义来加载相应的认证鉴别模块。然后把请求(即从应用程序那里得到的参数)传递给底层的认证鉴别模块,这时认证鉴别模块就可以根据要求执行具体的认证鉴别操作了。当认证鉴别模块执行完相应的操作后,再将结果返回给应用接口层,然后由接口层根据配置的具体情况将来自认证鉴别模块的应答返回给应用程序。

上面描述了 PAM 的各个组成部分以及整体的运作机理。下面将对 PAM 中的每一层分别加以介绍。

第一层:模块层。模块层处于整个 PAM 体系结构中的最底层,它向上为接口层提供用户认证鉴别等服务。也就是说所有具体的认证鉴别工作都是由该层的模块来完成的。对于应用程序,有些不但需要验证用户的口令,还可能要求验证用户的帐户是否已经过期。此外有些应用程序也许还会要求记录和更改当前所产生的会话类的相关信息或改变用户口令等。所以 PAM 在模块层除了提供鉴别模块外,同时也提供了支持帐户管理、会话管理以及口令管理功能的模块。当然,这四种模块并不是所有应用程序都必需的,而是根据需要灵活取舍。比如虽然 login 可能要求访问上述所有的四种模块, 但是 su 可能仅仅需要使用到鉴别模块的功能即可。至于如何取舍则涉及到接口层的 PAM API 和配置文件,这部分内容将在后文中加以介绍。

第二层:应用接口层。应用接口层位于 PAM 结构的中间部分,它向上为应用程序屏蔽了用户鉴别等过程的具体细节,向下则调用模块层中的具体模块所提供的特定服务。由上图可以看出,它主要由 PAM API 和配置文件两部分组成,下面将逐一介绍。

PAM API 可以分为两类:一类是用于调用下层特定模块的接口,这类接口与底层的模块相对应,包括:

  • 鉴别类接口:pam_authenticate()用于鉴别用户身份,pam_setcred()用于修改用户的私密信息。
  • 帐号类接口:pam_acct_mgmt()用于检查受鉴别的用户所持帐户是否有登录系统许可,以及该帐户是否已过期等。
  • 会话类接口:包括用于会话管理和记帐的 pam_open_session()和 pam_close_session()函数。
  • 口令类接口:包括用于修改用户口令的 pam_chauthtok()。

第二类接口通常并不与底层模块一一对应,它们的作用是对底层模块提供支持以及实现应用程序与模块之间的通信等。具体如下:

  • 管理性接口: 每组 PAM 事务从 pam_start()开始,结束于 pam_end()函数。接口 pam_get_item()和 pam_set_item()用来读写与 PAM 事务有关的状态信息。同时,能够用 pam_str()输出 PAM 接口的出错信息。
  • 应用程序与模块间的通讯接口:在应用程序初始化期间,某些诸如用户名之类的数据可以通过 pam_start()将其存放在 PAM 接口层中,以备将来底层模块使用。另外底层模块还可以使用 pam_putenv()向应用程序传递特定的环境变量,然后应用程序利用 pam_getenv()和 pam_getenvlist()读取这些变量。
  • 用户与模块间的通讯接口:pam_start()函数可以通过会话式的回调函数,让底层模块通过它们读写模块相关的鉴别信息,比如以应用程序所规定的方式提示用户输入口令。
  • 模块间通讯接口:尽管各模块是独立的,但是它们仍然能够通过 pam_get_item()和 pam_set_item()接口共享某些与鉴别会话有关的公用信息,诸如用户名、服务名、口令等。此外,这些 API 还可以用于在调用 pam_start()之后,让应用程序修改状态信息。
  • 读写模块状态信息的接口:接口 pam_get_data()和 pam_set_data()用以按照 PAM 句柄要求访问和更新特定模块的信息。此外,还可以在这些模块后附加一个清除数据函数,以便当调用 pam_end()时清除现场。

由于 PAM 模块随需加载, 所以各模块始化任务在第一次调用时完成。如果某些模块的清除任务必须在鉴别会话结束时完成,则它们应该使用 pam_set_data()规定清除函数,这些执行清除任务的函数将在应用程序调用 pam_end()接口时被调用。

以上介绍了 Linux 可插拔认证模块 PAM 的基本概念和分层体系结构,在后续文章里,将会介绍常见的 PAM 模块应用以及相关实例。

关于作者

王基立(Jerrywjl),红帽软件(北京)有限公司资深解决 方案架构师,熟悉红帽所有平台类产品和解决方案,拥有多 年的售前架构规划与售后技术支持经验。现主要负责华为、中兴等大型电信企业以及金融、政府、教育等行业客户在生产环境中的咨询、培训、现场实施和技术支持等工作。


感谢郑柯对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2012-02-29 00:008842

评论

发布
暂无评论
发现更多内容

云效 Projex是什么?Projex企业级高效研发项目管理平台

阿里云云效

阿里云 项目管理 研发 敏捷研发 项目协作

Python 中的鸭子类型和猴子补丁

AlwaysBeta

Python

“一只股票一张表”, TDengine 在青岛金融研究院量化分析场景中的应用

TDengine

数据库 tdengine 物联网

2022南京14届-物联网-博览会

InfoQ_caf7dbb9aa8a

[Day12]-[动态规划]-零钱兑换

方勇(gopher)

LeetCode 数据结构和算法

jackson学习之七:常用Field注解

程序员欣宸

4月月更

龙蜥社区成立DeepRec SIG,开源大规模稀疏模型深度学习引擎

OpenAnolis小助手

深度学习 开源 龙蜥社区 sig 稀疏模型

为什么要进行数字化转型

王字 Wannz

数字化生态 数字化转型 finclip 小程序容器

linux之chattr命令

入门小站

react源码解析8.render阶段

buchila11

React

云图说丨不同区块链之间如何跨链交互?

华为云开发者联盟

区块链 跨链 可信 可信跨链服务 跨链交互

坐实大数据资源调度框架之王,Yarn为何这么牛

华为云开发者联盟

大数据 hadoop mapreduce YARN 资源调度框架

生于彼,长于此:狗形机器人的中国情缘

脑极体

自己动手写Docker系列 -- 5.6实现删除容器

Go Docker 4月月更

2022南京14届-智慧工地-博览会

InfoQ_caf7dbb9aa8a

区块链一周热点回顾|虎符元宇宙建筑Hoo HQ已对外开放体验

区块链前沿News

虎符交易所

读《Software Engineering at Google》(01)

术子米德

架构师成长笔记

读《Software Engineering at Google》(02)

术子米德

架构师成长笔记

如何做好复盘

Hockor

复盘

腾讯一面:你平时怎么排查并调优慢 SQL 的

老周聊架构

MySQL 4月月更

设计消息队列存储消息数据的 MySQL 表格

「架构实战营」

react源码解析7.Fiber架构

buchila11

React

2022南京14届-人工智能-博览会

InfoQ_caf7dbb9aa8a

在线SVG在线编辑器

入门小站

工具

Retool 是什么,怎么样? —— Retool 低代码工具测评

蒋川

低代码 低代码开发平台 retool

如何使用参数化查询提高Cypher查询的性能

华为云开发者联盟

参数化 Cypher查询 华为云图引擎 GES 参数化查询

【PIMF】开源鸿蒙首款IDE低代码入门OpenHarmony应用开发

离北况归

低代码 OpenHarmony Openharmony啃论文俱乐部 OpenHarmony应用开发 可视化界面

Docker 实战教程之从入门到提高(二)

汪子熙

Docker 容器 虚拟化 docker image 4月月更

Linux驱动开发-编写RFID-RC522射频刷卡模块驱动

DS小龙哥

4月月更

Apache ShenYu源码阅读系列-Divide插件

子夜2104

健康码如何影响世界

王字 Wannz

小程序 微信 finclip 凡泰极客 健康码

Linux可插拔认证模块的基本概念与架构_Linux_王基立_InfoQ精选文章