Linux 系统上的每个文件和进程都属于特定的用户账户。 如果没有得到属主的许可,其他用户就不能访问这些对象,因此,这些约定有助于用户彼此之间不管是有意还是无意的错误行为。
系统文件和进程属于一个称为root的虚拟用户,也叫超级用户。与任何其他帐号一样,root 拥有的东西也受到保护,不受来自其他用户的干扰。
Root 可以充当任何文件或进程的属主,还可以执行一些特殊操作,而其他用户是无权执行这些操作的。 这个帐号的权限非常大,但如果是没有经过训练的用火或者是心怀恶意的用户使用这个帐号的话,将会非常危险。
一. 文件和进程的归属关系
每个文件都同时有一个属主(owner)和一个属组(group owner)。 文件的属主拥有一种不和系统上任何用户共享的特殊权限,即修改文件访问权限的能力。 具体而言,就是属主可以严格地设置文件的访问权限,让其他任何人都不能够访问这个文件。
尽管文件的属主总是一个人,但许多人都可以称为文件的属组成员,只要他们全部是一个Linux 组的成员即可。 组原本在/etc/group文件中进行定义,但是现在用户组饿信息保存在网络中的NIS或者LDAP 服务器上更为常见。
文件的属主指定属组成员可以对文件进行哪些操作。 这种机制能让同一个项目的成员之间共享文件。一个文件的这两种归属关系都可以用ls –l filename 命令来了解。如:
$ls –l /staff/scott/toto
-rw------- l scott staff 1258 jun 25 9:08 /staff/scott/toto
这个文件的属主是用户scott, 属组是staff组。
Linux 实际上用数字来确定属主和属组,而不是用它们的文件名称。 在最基本的情况下,用户标识号(User identification numbers:UID)被映射到/etc/passwd文件中的用户名上,而组标识号(Group identification Numbers:GID)被映射到/etc/group 文件中的组名上。 定义与UID和GID相对应的文件名称只是方便系统的现实用户使用。当诸如ls这样的命令要以人们可以阅读的格式来显示归属关系信息时,这些命令就必须在相应的文件或数据库中查出每个名字。
一个进程的属主可以向该进程发送信号,还可以减小(降低)该进程的调度优先级。 进程实际上至少有7个与之相关的标识:一个真实UID(real),一个有效UID(effective)和一个保存UID(saved);一个真实GID,一个有效GID和一个保存GID。 在linux 下,还有一个文件系统UID(filesyste),它只用确定文件的访问权限。 概括地说,真实ID用作记账,有效ID用来确定访问权限。 一般情况下,真实ID和有效ID 是相同的。
保存ID 没有直接作用。 他们能让程序几下一个不活动的ID供以后使用,减少需要用过大特权的机会。 文件系统ID 一般按NFS 的实现细节来解释,通常和有效ID 相同。
尽管通常对于一个进程来说不太可能会改变它自己的归属关系状态,但在一种特殊情形下,可以修改进程的有效UID和有效GID。 当执行设置了setuip或setgid 权限位的命令时,所得到的进程其有效UID或GID 可以设置为包含该程序的映像文件的UID或GID,而不是设置为运行该命令的用户的UID和GID。 这样一来,用户的权限就为此次执行该特定命令而得到提升。
利用Linux 的setuid 功能,普通用户可以以一种受限的并严格控制的方式来使用root帐号去运行程序。 如,用户运行用来修改其登陆口令的passwd命令就是一个setuid的程序。 它以一种严格限定的方式去修改/etc/shadow或者/etc/passwd 文件,然后退出执行。 因为这种受限任务有被滥用的可能,因此passwd命令在同意执行锁请求的修改以前,需要用户证实他们知道当前帐号的口令。
二. 超级用户
Root 帐号在定义上的特征是它的UID为0. Linux 并没有不许用户修改这个帐号上的用户名,也没有不许创建UID 为0的其他帐号,但这两种做法都非常不好。 像这样的修改有可能无意中破坏系统的安全性。 同时,当其他人不得不适应这种奇怪方式配置的系统时,也容易给他们带来混乱。
传统的Unix允许超级用户(也就是有效UID 为0的任何进程)在任何文件或进程上执行正当的操作。 此外,有些系统调用(对内核的请求)只能够由超级用户来执行,这类受限操作的一些例子有:
(1) 采用chroot命令来改变进程的根目录
(2) 创建设备文件
(3) 设置系统时钟
(4) 提高资源使用率的限度和进程的优先级
(5) 设置系统的主机名称
(6) 配置网络接口
(7) 打开特权网络端口(那些编号小于1024的端口)
(8) 关闭系统
例如,超级用户有权改变属主为root的进程的UID和GID。 Login 程序及其采用窗口形式的等价程序都是这样的例子, 这个在用户登陆到系统时提示用户输入口令的进程起初就是以root权限运行的。 如果所输入的用户名和口令是合法的话,login 就把它的UID和GID 改变成为该用户的UID和GID并启动该用户的用户环境。 一旦一个以root权限执行的进程已经改变了它的归属关系而成为一个普通的用户进程,那么它就不能在恢复它以前的特权状态了。
Linux 系统从理论上说也能把root 帐号的特权按照POSIX标准中有关权力(capability)的规定在做细分。 出于各种原因,其他也包括当前实现存在的问题,这项功能并没有最初体现的那样有帮助,对于系统管理员来说也没有那么适用。
三. 选择root的口令
Root口令的长度至少为8个字符,7个字符长度的口令其实非常容易破译。 在有些使用DES口令的系统上,使用长度超过8个字符的口令是没有什么用处的,以内只有前8个字符有意义。
让所选的root口令不那么容易被猜中或者反复试探找到,是非常重要的。理论上将,最安全的口令类型是由字符,标点符号和数字组成的随即序列。 但是这种类型的口令很难记住,并且一般来说输入也比较费劲。
可以采用2个单词中间加一个标点符号组成的口令或者采用一些短语来构成root口令。 一般遇到如下情况,就需要修改root口令:
(1) 至少每3个月左右
(2) 每次当有个知道口令的人离开公司
(3) 在认为安全性可能已经受到威胁的任何时候
四. 成为root用户
Root 不过是另一个用户而已,所以可以直接以root账户登陆进入系统。 但是,这样做没有留下以root身份执行的操作的记录。 而且如果有几个人都有访问root账户的权限,那么将不能够区分到底是谁在什么时候使用了root帐号。因此,在大多数系统禁用root在终端上以及通过网络来登陆系统。 或者说除了系统控制台之外的其他任何地方都禁止root登陆。
4.1 su :替换用户身份
访问root账户烧好一些的方式是使用su命令。 如果不带任何参数来调用su命令,那么它会提示用户输入root口令,然后启动一个rootshell。 这个shell 的特权一直到shell 终止(通过<control –D >或者exit 命令来终止)以前都保持有效。 Su 不记录以root身份执行了哪些命令,但它确实会创建一条日志记录来说明是谁在什么时候变成root.
Su命令也可以替代除了root意外的其他用户身份。 有时候,重现或者调试用户问题的唯一方法就是su为该用户的帐号,以便能够重现发生问题的环境。
如果知道某人的口令,那么通过执行su username就能够直接访问这个人的帐号。 与su 到root 帐号的情况一样,此时也会提示用户输入username的口令。 你也可以首先su 到root帐号,然后再su 到其他帐号,root帐号不需要提供密码就可以速到其他任何帐号。
最好是键入su命令的完整路径,如/bin/su,而不是依靠shell 为你找到这个命令。 这将在一定程度上防范已经溜入到搜索路径下名为su的程序,它们带有想要获取口令的企图。
4.2 sudo: 受限的su
由于超级用户帐号的特权不可分割,至少不能随意分割,所以很难既给某个人完成一件任务的权利而又不给这个人自由运行系统的权利。 而且如果root账户由几个管理员使用,那么对于是谁正在使用这个帐号或者谁使用这个帐号做了什么事情就只有非常模糊的认识了。 针对这个问题,最广泛的解决方案是使用一个叫作sudo的程序。
Sodu 采用命令行作为参数,然后以root身份(或者另外一个受限用户)执行。 Sudo 读取文件/etc/sudoers,这个文件列出了授权使用sudo 的人已经允许他们在每台主机上运行的命令。 如果提供给sudo 的命令允许运行,那么sudo 就提示输入这个用户自己的口令并执行命令。
使用sudo 的用户随后可以执行其他一些sudo 命令而不是再输入口令,除非在超过5min(时间长度可以配置)的时间内该用户没有再使用sudo。 这段超时时间可以作为一种最友善的保护,方式具有sudo特权的用户由于不注意而长时间地离开终端造成安全隐患。
Sudo 保存有一个日志,它记录执行命令行,命令行执行的主机,请求执行命令行的人,运行命令行的目录以及命令行被调用的时间。 这些信息可以通过syslog 进行记录或者被放入选定的文件中。 我们推荐使用syslog把日志项转发给一个安全的中央主机。
注意的是,/etc/sudoers中的命令采用完整路径来指定,这样做是为了防止人们以root身份去执行他们自己的脚本。 要修改/etc/sudoers, 请使用visudo命令, 这个命令检查以确保没有其他人正在编辑这个文件,接着调用一个编辑器编辑该文件,然后先验证文件编辑修改后的语法无误,再安装它。 最后这一步尤其重要,因为无效的sudoers 文件可能会不让用户再用sudo去修复它。
使用sudo具有如下一下好处:
(1) 由于有命令日志,因而极大地提高了安全审计的能力
(2) 操作员不需要不受限制的root特权就能够完成许多任务
(3) 真正的root口令可以只让一两个人知道
(4) 使用sudo 比运行su或者以root身份登陆进入系统更快
(5) 不需要改变root口令就能够收回一些特权
(6) 维护一个具有root特权的所有用户的规范列表
(7) 不经意遗留root shell 的概率降低了许多
(8) 可以使用单个文件来控制对整个网络的访问权限
Sudo 也有一些不足之处,如果突破了能执行sudu命令的个人帐号的安全防线,就等于突破了root帐号本身的安全防线。 对付这种威胁除了提醒能执行sodu 命令的用户在他们暂时成为root时保护好自己的帐号之外,就没有其他的措施了。 也可以定期用John the ripper 程序尝试破解一下sudoer口令。 确保用户选择了良好的口令。
Sodu 的命令日志机制可以用一些技巧暗中破坏,比如在允许执行的程序中使用shell的转义字符,或者如果允许sudo sh 和sudo su的话,则利用他们来破坏。
五. 其他的用户
在内核看来,root是具有特殊地位的唯一用户,但系统还定义了另外几个伪用户。管用的做法是用星号来替代这些特殊用户在/etc/passwd中被加密的口令字段,从而让这些用户的账户不能用来登陆进入系统。
5.1 bin: 系统命令的老属主
在一些比较老的Unix系统上,bin用户是包含系统命令的那些目录的属主,还是大多数命令本身的属主。 如今这种帐号经常被看作是多余的,或者可能有些不安全。 因此现代系统通常就只使用root帐号了。 另一方面,既然bin帐号是标准帐号,所以还真的不能废除它。
5.2 daemon:无特权系统软件的属主
有些文件和进程是操作系统的一部分,但不需要由root做其属主,这样的文件和进程就给了daemon。 其中的道理是,这种约束有助于避免采用root做属主所带来的危险。 出于类似的原因,还有一个叫作daemon的组。 和bin帐号类似,大多数Linux发型版本也不怎么用daemon帐号。
5.3 nobody : 普通NFS 用户
网络文件系统(network file system:NFS)在进行文件共享时,使用nobody帐号代表其他系统上的root用户。 为了去掉远程root用户的特权,远程UID为0的用户必须被映射成本地UID 0 之外的某个用户。 Nobody帐号就充当了这些远程root用户的一般替身。
由于nobody帐号应该代表yield普通的,权力相对来说比较小的用户,因此这个帐号不应该拥有任何文件。 如果nobody 帐号确实拥有文件的话,那么远程的root就可以控制这些文件。 Nobody 不应该拥有任何文件。
传统上给nobody用户的UID 是-1 或者-2, linux 内核仍然默认用UID 65534(-2的16位二进制补码)。 有些发行版本给nobody 指派一个小编号的UID,这样做比65534更合理,因为UID 是32位的。 唯一有问题的地方是exportfs 命令似乎不去看passwd文件,所以必须用annonuid选项明确告诉它给nobody用一个不同的UID。