Paranoid Penguin - Linux 文件系统安全,第二部分

作者:Mick Bauer

上次,我们从头开始了解了文件和目录权限——什么是用户和组,以及如何在文件和目录上设置和移除读取、写入和执行权限。在本专栏中,我们将研究一些更高级的权限类型,探索权限数字模式和 umask 命令,并了解如何使用 su 和 sudo 委派 root 权限。本文包含比上个月的文章更偏中级的信息,但希望它仍然有意义,即使您对权限的了解仅限于您上次在这里阅读的内容。

粘滞位

回想一下上个月 extreme_casseroles/ 目录的详细列表

drwxr-x--- 8  biff drummers 288 Mar 25 01:38 extreme_casseroles

还记得我们曾将此目录的组权限设置为 r-x,即组可读和组可执行,以便我们 drummers 组的成员可以进入此目录并享用其中存储的食谱。

假设我们的鼓手朋友 Biff 希望允许他的鼓手伙伴不仅可以阅读他的食谱,还可以添加他们自己的食谱。正如我们上次所见,他只需要为此目录设置组写入位,就像这样

chmod g+w ./extreme_casseroles

但是,这样做只有一个问题。写入权限包括在此目录中创建新文件以及删除文件的能力。有什么可以阻止他的鼓手伙伴删除其他人的食谱呢?那就是粘滞位。

在过去,粘滞位用于将文件(程序)写入内存,以便在调用时可以更快地加载。然而,在 Linux 上,它具有不同的功能。当您在目录上设置粘滞位时,它会限制人们删除该目录中内容的能力。也就是说,要删除目录中的给定文件,您必须拥有该文件或拥有该目录,即使您属于拥有该目录的组并且在该目录上设置了组写入权限。

要设置粘滞位,请发出命令

chmod +t directory_name

在我们的示例中,这将是chmod +t extreme_casseroles。如果我们现在通过使用带有 -d 选项的 ls 列出目录本身的详细列表,而不是其内容,即,ls -ld extreme_casseroles,我们看到

drwxrwx--T 8  biff drummers  288  Mar 25 01:38 extreme_casseroles

请注意权限末尾的 T。我们通常期望在那里看到 x 或 -,具体取决于目录是否是其他用户可写的。T 表示该目录不是其他用户可执行的,并且已设置粘滞位。小写 t 表示该目录是其他用户可执行的,并且已设置粘滞位。

为了说明此限制的影响,假设 extreme_casseroles/ 的内容列表如列表 1 所示。

列表 1. extreme_casseroles/ 的内容

drwxrwxr-T  3 biff drummers  192 2004-08-10 23:39 .
drwxr-xr-x  3 biff drummers 4008 2004-08-10 23:39 ..
-rw-rw-r--  1 biff drummers   18 2004-07-08 07:40 chocolate_turkey_casserole.txt
-rw-rw-r--  1 biff drummers   12 2004-08-08 15:10 pineapple_mushroom_surprise.txt
drwxr-xr-x  2 biff drummers   80 2004-08-10 23:28 src

进一步假设用户 crash 尝试删除文件 pineapple_mushroom_surprise.txt,crash 觉得这个文件令人反感。crash 期望这样做会成功,因为他属于 drummers 组,并且此文件上设置了组写入位。但是,请记住,biff 设置了父目录的粘滞位。因此,crash 尝试删除失败,如列表 2 所示。

列表 2. 尝试删除,已设置粘滞位

crash> rm pineapple_mushroom_surprise.txt
rm: cannot remove `pineapple_mushroom_surprise.txt':
Operation not permitted

关于粘滞位的另一个注意事项:它仅适用于目录的第一层向下。在列表 1 中,您可能已经注意到,除了两个令人讨厌的食谱外,extreme_casseroles/ 还包含另一个目录 src。src 的内容不会受到 extreme_casseroles 的粘滞位的影响,尽管目录 src 本身会受到影响。如果 biff 想要保护 src 的内容免受组删除,他需要设置 src 自己的粘滞位。

setuid 和 setgid

现在我们来介绍 UNIX 和 Linux 世界中最危险的两个权限位:setuid 和 setgid。如果在一个可执行二进制文件上设置了 setuid 位,则该程序将以其所有者的身份运行,无论谁执行它。同样,当在可执行文件上设置 setgid 位时,该程序将以拥有它的组的成员身份运行,同样与谁执行它无关。

当我说以...身份运行时,我的意思是程序以相同的权限运行。例如,假设 biff 编写并编译了一个 C 程序 killpms,它的行为与命令相同rm /extreme_casseroles/pineapple_mushroom_surprise.txt。进一步假设 biff 使用命令chmod +s ./killpms在 killpms 上设置了 setuid 位,并且还使其组可执行。killpms 的详细列表可能如下所示

-rwsr-xr--  1 biff drummers   22 2004-08-11 23:01 killpms

如果 crash 运行此程序,他最终可以成功完成删除菠萝蘑菇惊喜食谱的任务:killpms 就像 biff 执行它一样运行。当 killpms 尝试删除 pineapple_mushroom_surprise.txt 时,它会成功,因为该文件具有用户写入权限,并且 killpms 以其用户/所有者 biff 的身份运行。

重要警告

如果 setuid 和 setgid 设置在 root 或任何其他特权帐户或组拥有的任何文件上,则它们非常危险。我在这里说明 setuid 和 setgid 是为了让您了解它们的作用,而不是因为我认为您实际上应该将它们用于任何重要的事情。本文后面描述的 sudo 命令是委派 root 权限的更好工具。

如果您希望程序以 setuid 方式运行,则该程序必须是组可执行或其他人可执行的,原因我希望是显而易见的。此外,Linux 内核会忽略 shell 脚本上的 setuid 和 setgid 位。这些位仅适用于二进制(编译)可执行文件。

setgid 的工作方式相同,但使用组权限。如果您使用命令在可执行文件上设置 setgid 位chmod g+s 文件名,并且如果该文件也是其他人可执行的 (-r-xr-sr-x),则当执行该程序时,它将以该文件的组 ID 而不是执行它的用户的组 ID 运行。

在上面的示例中,如果我们更改 killpms 的其他权限为 r-x (chmod o+x killpms) 并使其成为 setgid (chmod g+s killpms),无论谁执行 killpms,killpms 都将行使 drummers 组的权限,因为 drummers 是 killpms 的组所有者。

setgid 和目录

目录呢?嗯,setuid 对目录没有影响,但 setgid 有影响,而且有点违反直觉。通常,当您创建文件时,它会自动归您的用户 ID 和您的(主)组 ID 所有。例如,如果 biff 创建了一个文件,则该文件的用户所有者是 biff,组所有者是 drummers,假设 drummers 是 biff 的主组,如 /etc/passwd 中所列。

但是,设置目录的 setgid 位会导致在该目录中创建的任何文件继承该目录的组所有者。如果系统上的用户倾向于属于辅助组并且经常创建需要与这些组的其他成员共享的文件,这将非常有用。例如,如果用户 animal 在 /etc/group 中被列为 drummers 的辅助成员,但在 /etc/passwd 中被列为 muppets 的主组,那么 animal 可以毫无问题地在 extreme_casseroles/ 目录中创建文件,该目录的权限设置为drwxrwx--T。但是,默认情况下,animal 的文件属于 muppets 组,而不是 drummers 组,因此除非 animal 手动重新分配其文件的组所有权 (chgrp drummers 新文件) 或重置其其他权限 (chmod o+rw 新文件),否则 drummers 的其他成员无法读取或写入 animal 的食谱。

另一方面,如果 biff 或 root 在 extreme_casseroles/ 上设置了 setgid 位 (chmod g+s extreme_casseroles),当 animal 在其中创建一个新文件时,该文件的组所有者将是 drummers,与 extreme_casseroles/ 本身完全相同。所有其他权限仍然适用;如果所讨论的目录一开始就不是组可写的,则 setgid 位不起作用,因为组成员无法在其中创建文件。

现在我们已经介绍了所有可能的权限:读取、写入、执行、粘滞位、setuid 和 setgid。如果您理解所有这六个,您可能在 Linux 用户中是少数。但是等等,还有更多!

数字模式

到目前为止,我们一直在使用助记符来表示权限——r 代表读取,w 代表写入等等。不用说,与所有其他事物一样,您的系统实际上使用数字来表示权限。chmod 命令识别助记符权限修饰符(u+rwx、go-w)和数字模式。

数字模式由四个数字组成:从左到右读取,它们分别代表特殊权限、用户权限、组权限和其他权限。回想一下,其他是用户权限或组权限未涵盖的其他用户的缩写。例如,0700 转换为未设置特殊权限、设置所有用户权限、未设置组权限和未设置其他权限。

每个权限都有一个数值,并且每个数字位置的权限是累加的:该数字表示您要设置的所有权限位的总和。例如,如果用户权限设置为 7,则表示 4(读取的值)加 2(写入的值)加 1(执行的值)。

正如我刚才提到的,基本数值是 4 代表读取,2 代表写入,1 代表执行。(我通过在脑海中重复短语“读-写-执行,4-2-1”来记住这些。)您可能会想知道为什么没有 3?因为这样,没有两种权限组合具有相同的总和。

特殊权限如下:4 代表 setuid,2 代表 setgid,1 代表粘滞位。例如,数字模式 3000 转换为 setgid 已设置、粘滞位已设置且未设置其他权限,实际上,这是一组无用的权限。

这是数字模式的另一个示例。如果我发出命令chmod 0644 mycoolfile,我正在设置 mycoolfile 的权限,如图 1 所示。

Paranoid Penguin - Linux Filesystem Security, Part II

图 1. mycoolfile 的权限

有关数字模式的更完整讨论,请参阅 coreutils 的 info 页面,节点 Numeric Modes。也就是说,输入命令info coreutils numeric.

umask

在结束其他几个主题之前,我想介绍最后一个特定于权限的命令。umask 是 bash shell 内置的命令,用于打印或设置您的默认权限掩码。要查看您的掩码,只需输入不带任何参数的 umask 命令;它会返回一个四位数字。在我的系统上,它看起来像列表 3。

列表 3. 检查我的默认权限掩码

mick@localhost:/home/mick> umask
0022

模式 0022 表示没有特殊权限,没有用户所有者权限,组和其他权限设置为写入,对吗?这怎么可能呢?

实际上,umask 处理的是掩码,而不是模式本身。0022 是从数字 0777 中减去的数字,以确定您创建的文件的数字模式:0777 – 0022 = 0755。

啊哈!所以,我创建的文件将用户所有者权限设置为读-写-执行 (7 = 4 + 2 + 1),并将组和其他权限设置为读-执行 (5 = 4 + 1)?对吗?几乎。umask 也恰好仅在目录上自动设置执行位。即使您的权限掩码包含执行权限,执行位也不会在您创建的常规文件上自动设置。因此,如果我的权限掩码是 0022,导致默认权限为 0755,并且我创建一个名为 default_file 的文件和一个名为 default_dir 的目录,则这两个项目的详细列表输出如列表 4 所示。

列表 4. 掩码为 0022 的文件和目录

-rwxr-xr-x   2 mick users      48 2004-08-13 08:31 default_dir
-rw-r--r--   1 mick users       4 2004-08-13 08:31 default_file

要更改您的默认权限掩码,只需发出带有新掩码作为其参数的 umask 命令。例如,如果我希望我的所有文件都具有组读取权限,但没有其他权限,这转换为数字模式 0740。如果我从 0777 中减去它,我会得到掩码 0037。因此,我输入的 umask 命令是umask 0037。但是,这个新掩码仅适用于我当前的会话以及我从中启动的任何新 shell。要使其持久化,我可以添加以下行umask 0037到我的 .bashrc 文件。

su 和 sudo

我应该说几句关于用户、组和权限的现实情况。UNIX 安全性的整个问题在于,在给定的系统上,权限和权限通常归结为 root 可以做任何事情,而用户几乎什么都做不了。

可悲的是,做一个快速的su -来暂时成为 root,比创建一个精细的组 membership 和权限系统来允许管理员和子管理员拥有他们需要的确切权限要容易得多。当然,您可以使用带有 -c 选项的 su 命令,该选项允许您指定一个以 root 身份运行的单个命令,而不是整个 shell 会话(例如,su -c rm somefile.txt),但这需要您输入 root 密码。让少数几个人知道 root 密码永远不是好事。

解决 root-takes-all 问题的另一种方法是使用基于角色的访问控制 (RBAC) 系统,例如 SELinux,它强制执行访问控制,从而降低 root 的有效权限。但是,这使得事情比设置有效的组和组权限更加复杂。这并不是说 SELinux 和其他系统不好——我喜欢 RBAC。

更好的折衷方案是使用 sudo 命令。sudo 是 superuser do 的缩写,它允许用户以 root 身份执行单个命令,而实际上不需要知道 root 密码。sudo 现在是大多数 Linux 发行版上的标准软件包。

sudo 通过文件 /etc/sudoers 配置,但不应直接编辑此文件。而是使用 visudo 命令,它会在该文件上打开编辑器;vi 是默认编辑器。您可以通过设置 EDITOR 环境变量来使用不同的编辑器。例如,要使用 /usr/bin/gedit,请执行以下操作

export EDITOR=/usr/bin/gedit

空间不允许我详细解释 sudoers 的语法;有关完整信息,请参阅 sudoers(5)、sudo(8) 和 visudo(8) 手册页。在本文提供的空间中,让我们快速浏览一个示例。

还记得用户 crash 寻求摆脱菠萝蘑菇惊喜的追求吗?尽管在这种情况下,这有点过分——我已经说明的权限技术就足够了——您可以利用 sudo 允许 crash 实现他的目标,假设您 (biff) 具有 root 权限。首先,成为 root (su -)。接下来,执行命令visudo。您现在处于 vi 会话中,正在编辑文件 /etc/sudoers;如果您是 vi 新手,请参阅 vi(1) 手册页。向下滚动到文件底部并添加以下行

crash localhost=/bin/rm /home/biff/extreme_casseroles/pineapple_mushroom_surprise.txt

保存并退出文件。

现在,为了做他的事,crash 输入命令

sudo rm /home/biff/extreme_casseroles/pineapple_mushroom_surprise.txt

,然后提示他输入密码。在他正确输入密码后,命令

/bin/rm /home/biff/extreme_casseroles/pineapple_mushroom_surprise.txt

以 root 身份执行,冒犯性文件就消失了。

或者,/etc/sudoers 中的行可能如下所示

crash localhost=/bin/rm /home/biff/extreme_casseroles/*

这样,crash 可以删除 extreme_casseroles/ 中的任何内容,而无需考虑粘滞位设置。

sudo 虽然很方便,但它是一个强大的工具,所以请明智地使用它;永远不应轻视 root 权限。最好谨慎地使用用户和组权限,而不是随意分配 root 权限,即使使用 sudo 也是如此。更好的是,如果风险足够高,请使用基于 RBAC 的系统,例如 SELinux。

现在就到这里。我希望您觉得本教程有用。下次见,请注意安全!

Mick Bauer,CISSP,是 Linux Journal 的安全编辑,也是明尼苏达州明尼阿波利斯市的 IS 安全顾问。他是 使用 Linux 构建安全服务器(O'Reilly & Associates,2002)的作者。

加载 Disqus 评论