10.7 Linux的安全性

Linux作为MINIX和UNIX的复制品,几乎从一开始就是一个多用户系统。这段历史意味着Linux从早期开始就建立了安全和信息访问控制。在接下来的几节里,我们将关注Linux安全性的一些方面。

10.7.1 基本概念

一个Linux系统的用户群体由一定数量的注册用户组成,其中每个用户拥有一个惟一的UID(用户ID)。UID是介于0到65 535之间的一个整数。文件(进程及其他资源)都标记了它的所有者的UID。尽管可以改变文件所有权,但是默认情况下,文件的所有者是创建该文件的用户。

用户可以被分组,其中每组同样由一个16位的整数标记,叫做GID(组ID)。给用户分组通过在系统数据库中添加一条记录指明哪个用户属于哪个组的方法手工(由系统管理员)完成。一个用户可以同时属于多个组。为简单起见,我们不再深入讨论这个问题。

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

Linux中的基本安全机制很简单。每个进程记录它的所有者的UID和GID。当一个文件被创建时,它的UID和GID被标记为创建它的进程的UID和GID。该文件同时获得由该进程决定的一些权限。这些权限指定所有者、所有者所在组的其他用户及其他用户对文件具有什么样的访问权限。对于这三类用户而言,潜在的访问权限为读、写和执行,分别由r、w和x标记。当然,执行文件的权限仅当文件是可执行二进制程序时才有意义。试图执行一个拥有执行权限的非可执行文件(即,并非由一个合法的文件头开始的文件)会导致错误。因为有三类用户,每类用户的权限由3个比特位标记,那么9个比特位就足够标记访问权限。图10-37给出了一些9位数字及其含义的例子:

阅读 ‧ 电子书库
图 10-37 文件保护模式的例子

图10-37前两行的意思很清楚,允许所有者以及与所有者同组的人所有权限。接下来的一行允许所有者同组用户读权限但是不可以改变其内容,而其他用户没有任何权限。第四行通常用于所有者想要公开的数据文件。类似地,第五行通常用于所有者想要公开的程序。第六行剥夺了所有用户的任何权利。这种模式有时用于伪文件来实现相互排斥,因为想要创建一个同名的文件的任何行为都将失败。如果多个进程同时想要创建这样一个文件作为锁,那么只有一个能够创建成功。最后一个例子相当奇怪,因为它给组以外其他用户更多的权限。但是,它的存在是符合保护规则的。幸运的是,尽管没有任何文件访问权限,但是所有者可以随后改变保护模式。

UID为0的用户是一个特殊用户,称为超级用户(或者根用户)。超级用户能够读和写系统中的任何文件,不论这个文件为谁所有,也不论这个文件的保护模式如何。UID为0的进程拥有调用一小部分受保护的系统调用的权限,而普通用户是不能调用这些系统调用的。一般而言,只有系统管理员知道超级用户的密码,但是很多学生寻找系统安全漏洞想让自己能够不用密码就可以以超级用户的身份登录,并且认为这是一种了不起的行为。管理人员往往对这种行为很不满。

目录也是一种文件,并且具有普通文件一样的保护模式。不同的是,目录的x比特位表示查找权限而不是执行权限。因此,如果一个目录具有保护模式rwxr-xr-x,那么它允许所有者读、写和查找目录,但是其他人只可以读和查找,而不允许从中添加或者删除文件。

与I/O相关的特殊文件拥有与普通文件一样的保护位。这种机制可以用来限制对I/O设备的访问权限。例如,假设打印机特殊文件,/dev/lp,可以被根用户或者一个叫守护进程的特殊用户拥有,具有保护模式rw-------,从而阻止其他所有人对打印机的访问权限。毕竟,如果每个人都可以任意使用打印机,那么就会发生混乱。

当然,让/dev/lp被守护进程以保护模式rw-------拥有,意味着其他任何人都不可以使用打印机,但是这种做法限制了很多合法的打印要求。事实上,允许对I/O设备及其他系统资源进行受控访问的做法具有一个更普遍的问题。

这个问题通过增加一个保护位SETUID到之前的9个比特位来解决。当一个进程的SETUID位打开,它的有效UID将变成相应可执行文件的所有者的UID,而不是当前使用该进程的用户的UID。当一个进程试图打开一个文件时,系统检查的将是它的有效UID,而不是真正的UID。将访问打印机的程序设置为被守护进程所有,同时打开SETUID位,这样任何用户都可以执行该程序,并拥有守护进程的权限(例如访问/dep/lp),但是这仅限于运行该程序(例如给打印任务排序)。

许多敏感的Linux程序被根用户所有,但是打开它们的SETUID位。例如,允许用户改变密码的程序需要写password文件。允许password文件公开可写显然不是个好主意。解决的方法是,提供一个被根用户所有同时SETUID位打开的程序。虽然该程序拥有对password文件的全部权限,但是它仅仅改变调用该程序的用户的密码,而不允许其他任何的访问权限。

除了SETUID位,还有一个SETGID位,工作原理同SETUID类似。它暂时性地给用户该程序的有效GID。然而在实践中,这个位很少用到。