第 4 章 认证和访问控制

目录

4.1. 一般的 Unix 认证
4.2. 管理账号和密码信息
4.3. 好密码
4.4. 设立加密的密码
4.5. PAM 和 NSS
4.5.1. PAM 和 NSS 访问的配置文件
4.5.2. 现代的集中式系统管理
4.5.3. “为什么 GNU su 不支持 wheel 组”
4.5.4. 严格的密码规则
4.6. 安全认证
4.6.1. 确保互联网上的的密码安全
4.6.2. 安全 Shell
4.6.3. 互联网额外的安全方式
4.6.4. root 密码安全
4.7. 其它的访问控制
4.7.1. 访问控制列表(ACLs)
4.7.2. sudo
4.7.3. PolicyKit
4.7.4. 限制访问某些服务端的服务
4.7.5. Linux 安全特性

当用户(或程序)需要访问系统时,需要进行认证,确认身份是受信任。

[警告] 警告

PAM 的配置错误可能会锁住你的系统。你必须有一个准备好的救援 CD,或者设立一个替代的 boot 分区。为了恢复系统,你需要使用它们启动系统并纠正错误。

一般的 Unix 认证由 PAM (Pluggable Authentication Modules,即可插入的验证模块) 下的 pam_unix(8) 模块提供。它的 3 个重要文件如下,其内的条目使用 “:” 分隔。


/etc/passwd” 包含下列内容。

 ...
user1:x:1000:1000:User1 Name,,,:/home/user1:/bin/bash
user2:x:1001:1001:User2 Name,,,:/home/user2:/bin/bash
 ...

passwd(5) 中所述,这个文件中被 “:” 分隔的每项含义如下。

  • 登录名

  • 密码形式说明

  • 数字形式的用户 ID

  • 数字形式的组 ID

  • 用户名或注释字段

  • 用户家目录

  • 可选的用户命令解释器

/etc/passwd” 的第二项曾经被用来保存加密后的密码。在引入了 “/etc/shadow” 后,该项被用来说明密码形式。


/etc/shadow” 包含下列内容。

 ...
user1:$1$Xop0FYH9$IfxyQwBe9b8tiyIkt2P4F/:13262:0:99999:7:::
user2:$1$vXGZLVbS$ElyErNf/agUDsm1DehJMS/:13261:0:99999:7:::
 ...

shadow(5) 中所述,这个文件中被 “:” 分隔的每项含义如下。

  • 登录名

  • 加密后的密码(开头的 “$1$” 表示使用 MD5 加密。“*” 表示无法登录。)

  • 最后一次修改密码的时间,其表示从 1970 年 1 月 1 日起的天数

  • 允许用户再次修改密码的天数间隔

  • 用户必须修改密码的天数间隔

  • 密码失效前的天数,在此期间用户会被警告

  • 密码失效后的天数,在次期间密码依旧会被接受

  • 账号失效的时间,其表示从 1970 年 1 月 1 日起的天数

/etc/group” 包含下列内容。

group1:x:20:user1,user2

group(5) 中所述,这个文件中被 “:” 分隔的每项含义如下。

  • 组名称

  • 加密后的密码(不会被真正使用)

  • 数字形式的组 ID

  • 使用 “,” 分隔的用户名列表

[注意] 注意

/etc/gshadow” 为 “/etc/group” 提供了与 “/etc/shadow” 相似的功能,但没有被真正地使用。

[注意] 注意

如果"auth optional pam_group.so" 这行添加到了"/etc/pam.d/common-auth",并且在"/etc/security/group.conf" 里进行了设置,一个用户的实际组就可以被动态添加。参见 pam_group(8).

[注意] 注意

base-passwd 软件包包含了一份用户和组的官方文档:“/usr/share/doc/base-passwd/users-and-groups.html”。

下面是一些管理账号信息的重要命令。


其中的一些功能只能被 root 使用。密码和数据的加密参见 crypt(3)。

[注意] 注意

在设置了 PAM 和 NSS 的系统上(例如 Debian salsa 机器),本地的 “/etc/passwd”、“/etc/group” 和 “/etc/shadow” 可能不会被系统激活使用。上述的命令即使处于这种环境下依旧是有效的。

在系统安装时建立一个账号或使用 passwd(1) 命令时,你应该选择一个好密码,它应该由 6 到 8 个字符组成,其中包含下列根据 passwd(1) 设定的每个组合中的一个或多个字符。

  • 小写字母

  • 数字 0 到 9

  • 标点符号

[警告] 警告

密码中不要使用可以猜到的词。账号名、身份证号码、电话号码、地址、生日、家庭成员或宠物的名字、字典单词、简单的字符序列(例如 “12345” 或 “qwerty”)等都是糟糕的选择。

下面是一些用于 生成加盐的加密密码 的独立工具。


现代的类 Unix 系统(例如 Debian 系统)提供 PAM (Pluggable Authentication Modules,插入式验证模块)NSS(Name Service Switch,名称服务切换) 机制给本地系统管理员,使他们能够配置自己的系统。它们的功能可以概括为以下几点。

  • PAM 给应用软件提供了一个灵活的认证机制,因此涉及到了密码数据的交换。

  • NSS 提供了一个灵活的名称服务机制,它经常被 C 标准库使用,使例如 ls(1) 和 id(1) 这样的程序获得用户和组名称。

PAM 和 NSS 系统必须保持配置一致。

PAM 和 NSS 系统中重要的软件包如下。


  • libpam-doc 中 “The Linux-PAM System Administrators' Guide” 是了解 PAM 配置的必要文档。

  • glibc-doc-reference 中的 “System Databases and Name Service Switch” 是了解 NSS 配置的重要文档。

[注意] 注意

你可以使用 “aptitude search 'libpam-|libnss-'” 命令查看更多的相关软件包。NSS 缩写也可能意味着 “Network Security Service,网络安全服务”,它不同于 “Name Service Switch,名称服务切换”。

[注意] 注意

PAM 是用来为每个程序使用系统范围的默认值来初始化环境变量的最基础方法。

systemd 下, libpam-systemd 软件包被安装用来管理用户登录,通过为 logindsystemd 控制组层级中注册用户会话来实现。参见 systemd-logind(8)、logind.conf(5)和 pam_systemd(8)。

现代的集中式系统管理可以使用集中式的轻量目录访问协议(LDAP)服务器进行部署,从而通过网络管理许多类 Unix 和 非类 Unix 系统。轻量目录访问协议的开源实现是 OpenLDAP 软件

LDAP 服务器使用带有 PAM 和 NSS 的libpam-ldaplibnss-ldap 软件包为 Debian 系统提供账号信息。需要一些动作来启用 LDAP(我没有使用过这个设置,并且下面的信息纯粹是第二手的信息。请在这种前提下阅读下列内容。)。

  • 你通过运行一个程序,例如独立的 LDAP 守护进程 slapd(8),来建立集中式的 LDAP 服务器。

  • 你在 “/etc/pam.d/” 目录中的 PAM 配置文件里,使用 “pam_ldap.so” 替代默认值 “pam_unix.so”。

    • Debian 使用 “/etc/pam_ldap.conf” 作为 libpam-ldap 的配置文件,“/etc/pam_ldap.secret” 作为保存 root 密码的文件。

  • 你在 “/etc/nsswitch.conf” 文件中改变 NSS 配置,使用 “ldap” 替代默认值(“compat” 或 “file”)。

    • Debian 使用 “/etc/libnss-ldap.conf” 作为 libnss-ldap 的配置文件。

  • 为了密码的安全,你必须让 libpam-ldap 使用 SLL(或 TLS)连接。

  • 为了确保 LDAP 网络开销数据的完整性,你必须让 libpam-ldap 使用 SLL(或 TLS)连接。

  • 为了减少 LDAP 网络流量,你应该在本地运行 nscd(8) 来缓存任何 LDAP 搜索结果。

参见由 libpam-doc 软件包提供的 pam_ldap.conf(5) 中的文档和 “/usr/share/doc/libpam-doc/html/”,以及 glibc-doc 软件包提供的 “info libc 'Name Service Switch'”。

类似地,你可以使用其它方法来设置另一种集中式的系统。

[注意] 注意

这里的信息也许不能完全满足你的安全需求,但这里应当是一个好的起点

安全 Shell (SSH) 程序使用安全认证来提供不安全网络上两个不可信任主机之间的安全加密通讯。它由 OpenSSH 客户端, ssh(1), 和 OpenSSH 后台守护进程(daemon), sshd(8)组成.SSH 使用端口转发特性,可以给 POP 和 X 之类的不安全的协议通讯建立隧道,使其可以在互联网上安全传输。

客户端可以使用如下方式来认证自己:基于主机的认证、公钥认证、质疑应答认证、密码认证。使用公钥认证,可以实现远程免密码登录。参见 第 6.3 节 “服务器远程访问和工具 (SSH)”.

为阻止人们使用 root 权限访问你的机器,你需要做下面的操作。

  • 阻止对硬盘的物理访问

  • 锁住 UEFI/ BIOS 来阻止从可移动介质启动

  • 为 GRUB 交互式会话设置密码

  • 锁住 GRUB 菜单,禁止编辑

如果可以物理访问硬盘,则可以使用下面的步骤,相对简单的重置密码。

  1. 将硬盘拿到一个可以设置 UEFI/BIOS 从 CD 启动的电脑。

  2. 使用紧急介质启动系统(Debian 启动磁盘, Knoppix CD, GRUB CD, …)。

  3. 用读写访问挂载根分区。

  4. 编辑根分区的"/etc/passwd"文件,使 root 账户条目的第二段为空。

对于 grub-rescue-pc ,即使用紧急介质启动的电脑,如果有编辑 GRUB 菜单条目 (参见 第 3.1.2 节 “第二阶段:引载加载程序”) 的权限,在启动时,使用下面的步骤更加简单。

  1. 使用内核参数启动系统来修改一些事情,比如说,"root=/dev/hda6 rw init=/bin/sh".

  2. 编辑 "/etc/passwd" 文件,使 root 账户条目的第二段为空。

  3. 重启系统。

系统的 root shell 现在可以无密码访问了。

[注意] 注意

一旦某人拥有 root shell 访问权限,他能够访问任何内容,并可以重设系统上的任何密码。此外,他可以使用 johncrack 等软件包的暴力破解工具来比较所有用户的密码 (参见 第 9.5.11 节 “系统安全性和完整性检查”)。被破解的密码,可以用来和其它系统进行比较。

为避免这些相关问题,仅有的理论上的软件解决方案是使用 dm-crypt 和 initramfs (参见 第 9.9 节 “数据加密提示”)加密 root 分区(或 "/etc" 分区) 。这样的话,你总是需要密码来启动系统。

在密码基于认证和文件权限之外,系统也有其它的访问控制。

[注意] 注意

参见 第 9.4.16 节 “Alt-SysRq 键” 来限制内核的安全警告密钥(SAK)功能。

访问控制列表 ACL 是在 第 1.2.3 节 “文件系统权限” 里面解释的普通权限的一个超集。

在现代桌面环境中,你会遇到 ACL 行为。比如,当一个已经格式化的 USB 存储设备自动挂载到 "/media/penguin/USBSTICK",一个普通用户 penguin 能够执行:

 $ cd /media/penguin
 $ ls -la
total 16
drwxr-x---+ 1 root    root    16 Jan 17 22:55 .
drwxr-xr-x  1 root    root    28 Sep 17 19:03 ..
drwxr-xr-x  1 penguin penguin 18 Jan  6 07:05 USBSTICK

在第 11 列的 "+" 表示 ACL 在使用。如果没有 ACL,一个普通用户 penguin 应该不能够像这样列出目录内容,因为 penguin 不在 root 组。你能够按如下方式查看 ACL:

 $ getfacl .
# file: .
# owner: root
# group: root
user::rwx
user:penguin:r-x
group::---
mask::r-x
other::---

这里:

  • "user::rwx"、"group::---" 和 "other::---" 相应的为普通所有者、组和其它人的权限。

  • ACL "user:penguin:r-x" 运行普通用户 penguin 有 "r-x" 权限。这个能够让 "ls -la" 列出目录内容。

  • ACL "mask::r-x" 设置上层绑定权限。

更多信息参见 "POSIX Access Control Lists on Linux"、acl(5)、 getfacl(1) 和 setfacl

sudo(8) 程序是为了使一个系统管理员可以给用户受限的 root 权限并记录 root 活动而设计的。sudo 只需要一个普通用户的密码。安装 sudo 软件包并通过设置 “/etc/sudoers” 中的选项来使用它。参见 “/usr/share/doc/sudo/examples/sudoers” 和 第 1.1.12 节 “sudo 配置” 中的配置示例。

我将 sudo 用于单用户系统(参见 第 1.1.12 节 “sudo 配置”)是为了防止自己可能做出的愚蠢行为。就我个人而言,我认为使用 sudo 会比使用 root 账号操作系统来得好。例如,下列命令将 “some_file” 的拥有者改变为 “my_name”。

$ sudo chown my_name some_file

当然如果你知道 root 密码(比如自行安装 Debian 的用户所做的),任何用户账号都可以使用 “su -c” 让任何命令以 root 运行。

PolicyKit 是在类 Unix 操作系统中控制整个系统权限的一个操作系统组件。

较新的 GUI 图形界面程序设计时便考虑到了不作为特权进程来运行。它们通过 PolicyKit 来和特权进程通信,从而执行管理操作。

在 Debian 系统中,PolicyKit 限制了属于 sudo 组的用户账号的这种操作。

参见 polkit(8)。

对系统安全而言,尽可能的禁用服务程序,是一个好的主意。网络服务是危险的。有不使用的服务,不管是直接由后台守护进程(daemon)激活,还是通过super-server 程序激活,都被认为是安全风险。

许多程序,比如说 sshd(8), 使用基于 PAM 的访问控制。也还有许多方式来限制访问一些服务端的程序。

参见 第 3.5 节 “系统管理”第 4.5.1 节 “PAM 和 NSS 访问的配置文件”第 5.7 节 “Netfilter 网络过滤框架”

[提示] 提示

NFS 和其它基于 RPC 的程序,需要激活 Sun RPC 服务。

[提示] 提示

如果你远程访问最新的 Debian 系统有问题,看下在"/etc/hosts.deny"里是否存在"ALL: PARANOID"这样讨厌的配置,请把它注释掉。(但是你必须注意这种行为所带来的安全风险。)

Linux 内核已经发展和支持在传统的 UNIX 实现里面没有的安全特征。

Linux 支持 扩展属性,扩展了传统的 UNIX 属性 (参见 xattr(7))。

Linux 把传统的超级用户相关的特权分开到不同的单元,被称为 capabilities(7),它能够独立的启用和禁用。从 2.2 版本内核开始,Capabilities 是一个线程独立的属性。

Linux Security Module (LSM) 安全模块框架 提供了一个多方面的安全检查机制,和新的内核扩展关联。例如:

这些扩展紧缩的权力模型比普通的类 Unix 安全模型策略更加严格,甚至 root 的权力也被限制。建议你阅读 kernel.org 上的 Linux 安全模块(LSM)框架文档

Linux 的 namespaces 封装了一个全局系统资源到一个抽象的概念,全局系统资源在 namespace 内对进程可见,并且 namespace 有它们自己的全局资源隔离实例。 对其它进程全局资源的可见性的改变是,同一个 namespace 的成员可见,但是对非同一个 namespace 的其它进程不可见。从内核 5.6 版本起,有 8 种 namespaces (参见 namespaces(7), unshare(1), nsenter(1))。

在 Debian 11 Bullseye (2021) 中, Debian 使用 unified cgroup hierarchy(统一 cgroup 层级架构) (亦称为 cgroups-v2)。

namespacescgroups 一起来隔离它们的进程,允许资源控制的使用示例是:

这些功能不能够通过 第 4.1 节 “一般的 Unix 认证” 实现。这些高级话题大部分超出了本介绍文档的范围。