5.1 用户身份与能力
Linux 系统的管理员之所以是 root,并不是因为它的名字叫 root,而是因为该用户的身份号码即 UID(User IDentification)的数值为 0。在 Linux 系统中,UID 就相当于我们的身份证号码一样具有唯一性,因此可通过用户的 UID 值来判断用户身份。在 RHEL 7 系统中,用户身份有下面这些。
- 管理员 UID 为 0:系统的管理员用户。
- 系统用户 UID 为 1~999: Linux 系统为了避免因某个服务程序出现漏洞而被黑客提权至整台服务器,默认服务程序会有独立的系统用户负责运行,进而有效控制被破坏范围。
- 普通用户 UID 从 1000 开始:是由管理员创建的用于日常工作的用户。
需要注意的是,UID 是不能冲突的,而且管理员创建的普通用户的 UID 默认是从 1000 开始的(即使前面有闲置的号码)。
为了方便管理属于同一组的用户,Linux 系统中还引入了用户组的概念。通过使用用户组号码(GID,Group IDentification),我们可以把多个用户加入到同一个组中,从而方便为组中的用户统一规划权限或指定任务。假设有一个公司中有多个部门,每个部门中又有很多员工。如果只想让员工访问本部门内的资源,则可以针对部门而非具体的员工来设置权限。例如,可以通过对技术部门设置权限,使得只有技术部门的员工可以访问公司的数据库信息等。
另外,在 Linux 系统中创建每个用户时,将自动创建一个与其同名的基本用户组,而且这个基本用户组只有该用户一个人。如果该用户以后被归纳入其他用户组,则这个其他用户组称之为扩展用户组。一个用户只有一个基本用户组,但是可以有多个扩展用户组,从而满足日常的工作需要。
5.1.1 useradd 命令
用途:创建新的用户或更改用户的信息。
使用 useradd
指令所建立的帐号,实际上是保存在/etc/passwd文本文件中。默认的用户家目录会被存放在 /home 目录中,默认的 Shell 解释器为 /bin/bash,而且默认会创建一个与该用户同名的基本用户组。
格式:useradd [选项] 用户名
参数 | 作用 |
---|---|
-d | 指定用户的家目录(默认为/home/username) |
-e | 账户的到期时间,格式为 YYYY-MM-DD. |
-u | 指定该用户的默认 UID |
-g | 指定一个初始的用户基本组(必须已存在) |
-G | 指定一个或多个扩展用户组 |
-N | 不创建与用户同名的基本用户组 |
-s | 指定该用户的默认 Shell 解释器 |
下面我们创建一个普通用户并指定家目录的路径、用户的 UID 以及 Shell 解释器。在下面的命令中,请注意/sbin/nologin,它是终端解释器中的一员,与 Bash 解释器有着天壤之别。一旦用户的解释器被设置为 nologin,则代表该用户不能登录到系统中:
[redhat@linuxprobe ~]$ useradd -d /home/linux -u 8888 -s /sbin/nologin linuxprobe
[redhat@linuxprobe ~]$ id linuxprobe
uid=8888(linuxprobe) gid=8888(linuxprobe) groups=8888(linuxprobe)
5.1.2 groupadd 命令
用途:创建用户组。
格式:groupadd [选项] 群组名
为了能够更加高效地指派系统中各个用户的权限,在工作中常常会把几个用户加入到同一个组里面,这样便可以针对一类用户统一安排权限。创建用户组的步骤非常简单,例如使用如下命令创建一个用户组 ronny:
groupadd ronny
5.1.3 usermod 命令
用途:修改用户的属性。
用户的信息保存在 /etc/passwd 文件中,可以直接用文本编辑器来修改其中的用户参数项目,也可以用 usermod
命令修改已经创建的用户信息,诸如用户的 UID、基本/扩展用户组、默认终端等。
格式:usermod [选项] 用户名
参数 | 作用 |
---|---|
-c | 填写用户账户的备注信息 |
-d -m | 参数-m 与参数-d 连用,可重新指定用户的家目录并自动把旧的数据转移过去 |
-e | 账户的到期时间,格式为 YYYY-MM-DD |
-g | 变更所属用户组 |
-G | 变更扩展用 |
-L | 锁定用户禁止其登录系统 |
-U | 解锁用户,允许其登录系统 |
-s | 变更默认终端 |
-u | 修改用户的 UID |
将用户 linuxprobe 加入到 root 用户组中,这样扩展组列表中则会出现 root 用户组的字样,而基本组不会受到影响:
[redhat@linuxprobe ~]$ id linuxprobe
uid=1000(linuxprobe) gid=1000(linuxprobe) groups=1000(linuxprobe)
[redhat@linuxprobe ~]$ usermod -G root linuxprobe
[redhat@linuxprobe ~]$ id linuxprobe
uid=1000(linuxprobe) gid=1000(linuxprobe) groups=1000(linuxprobe),0(root)
试用 -u
参数修改 linuxprobe 用户的 UID 号码值。除此之外,我们还可以用 -g
参数修改用户的基本组 ID,用 -G
参数修改用户扩展组 ID。
[redhat@linuxprobe ~]$ usermod -u 8888 linuxprobe
[redhat@linuxprobe ~]$ id linuxprobe
uid=8888(linuxprobe) gid=1000(linuxprobe) groups=1000(linuxprobe),0(root)
5.1.4 passwd 命令
用途:修改用户密码、过期时间、认证信息等。
普通用户只能使用 passwd 命令修改自身的系统密码,而 root 管理员则有权限修改其他所有人的密码。更酷的是,root 管理员在 Linux 系统中修改自己或他人的密码时不需要验证旧密码,这一点特别方便。既然 root 管理员可以修改其他用户的密码,就表示完全拥有该用户的管理权限。
格式:passwd [选项] [用户名]
参数 | 作用 |
---|---|
-l | 锁定用户,禁止其登录 |
-u | 解除锁定,允许用户登录 |
–stdin | 允许通过标准输入修改用户密码,如echo “NewPassWord” |
-d | 使该用户可用空密码登录系统 |
-e | 强制用户在下次登录时修改密码 |
-S | 显示用户的密码是否被锁定以及密码所采用的加密算法名称 |
[root@linuxprobe ~]# passwd
Changing password for user root.
New password: 此处输入密码值
Retype new password: 再次输入进行确认
passwd: all authentication tokens updated successfully.
[root@linuxprobe ~]# passwd linuxprobe
Changing password for user linuxprobe.
New password: 此处输入密码值
Retype new password: 再次输入进行确认
passwd: all authentication tokens updated successfully.
假设有位同事正在度假,而且假期很长,那么可以使用 passwd
命令禁止该用户登录系统,等假期结束回归工作岗位时,再使用该命令允许用户登录系统,而不是将其删除。这样既保证了这段时间内系统的安全,也避免了频繁添加、删除用户带来的麻烦:
[root@linuxprobe ~]# passwd -l linuxprobe
Locking password for user linuxprobe.
passwd: Success
[root@linuxprobe ~]# passwd -S linuxprobe
linuxprobe LK 2017-12-26 0 99999 7 -1 (Password locked.)
[root@linuxprobe ~]# passwd -u linuxprobe
Unlocking password for user linuxprobe.
passwd: Success
[root@linuxprobe ~]# passwd -S linuxprobe
linuxprobe PS 2017-12-26 0 99999 7 -1 (Password set, SHA512 crypt.)
5.1.5 userdel 命令
用途:删除用户。
在执行删除操作时,该用户的家目录默认会保留下来,此时可以使用 -r
参数将其删除。
格式:userdel [选项] 用户名
参数 | 作用 |
---|---|
-f | 强制删除用户 |
-r | 同时删除用户及用户家目录 |
[root@linuxprobe ~]# id linuxprobe
uid=8888(linuxprobe) gid=1000(linuxprobe) groups=1000(linuxprobe),0(root)
[root@linuxprobe ~]# userdel -r linuxprobe
[root@linuxprobe ~]# id linuxprobe
id: linuxprobe: no such use
5.2 文件权限与归属
尽管在 Linux 系统中一切都是文件,但是每个文件的类型不尽相同,因此 Linux 系统使用了不同的字符来加以区分,常见的字符如下所示。
- -:普通文件
- d:目录文件
- l:链接文件
- b:块设备文件
- c:字符设备文件
- p:管道
在 Linux 系统中,每个文件都有所属的所有者和所有组,并且规定了文件的所有者、所有组以及其他人对文件所拥有的 可读(r)、可写(w)、可执行(x) 等权限。
对于一般文件来说,权限比较容易理解:可读 表示能够读取文件的实际内容;可写 表示能够编辑、新增、修改、删除文件的实际内容;可执行则表示能够运行一个脚本程序。
对目录文件来说,可读 表示能够读取目录内的文件列表;可写 表示能够在目录内新增、删除、重命名文件;可执行 则表示能够进入该目录。
文件的读、写、执行权限可以简写为 rwx,亦可分别用数字 4、2、1 来表示,文件所有者、所属组及其他用户权限之间无关联,如下表所示。
权限分配 | 文件所有者 | 文件所属组 | 其他用户 |
---|---|---|---|
权限项 | 读 写 执行 | 读 写 执行 | 读 写 执行 |
字符表示 | r w x | r w x | r w x |
数字表示 | 4 2 1 | 4 2 1 | 4 2 1 |
5.3 文件的特殊权限
5.3.1 SUID
SUID 是一种对二进制程序进行设置的特殊权限,可以让二进制程序的执行者临时拥有属主的权限(仅对拥有执行权限的二进制程序有效)。
例如,所有用户都可以执行 passwd
命令来修改自己的用户密码,而用户密码保存在 /etc/shadow 文件中。仔细查看这个文件就会发现它的默认权限是 000,也就是说除了 root 管理员以外,所有用户都没有查看或编辑该文件的权限。但是,在使用 passwd
命令时如果加上 SUID 特殊权限位,就可让普通用户临时获得程序所有者的身份,把变更的密码信息写入到 shadow 文件中。
[root@linuxprobe ~]# ls -l /etc/shadow
----------. 1 root root 1004 Jan 3 06:23 /etc/shadow
[root@linuxprobe ~]# ls -l /bin/passwd
-rwsr-xr-x. 1 root root 27832 Jan 29 2017 /bin/passwd
-rwxrwxrwx
—> -rwsrwxrwx
-rw-rwxrwx
—> -rwSrwxrwx
执行命令如下:
chmod u+s FILE_NAME
5.3.2 SGID
SGID 主要实现如下两种功能:
- 让执行者临时拥有属组的权限(对拥有执行权限的二进制程序进行设置
- 在某个目录中创建的文件自动继承该目录的用户组(只可以对目录进行设置)
SGID 的第一种功能是参考 SUID 而设计的,不同点在于执行程序的用户获取的不再是文件所有者的临时权限,而是获取到文件所属组的权限。举例来说,在早期的 Linux 系统中,/dev/kmem 是一个字符设备文件,用于存储内核程序要访问的数据,权限为:
cr--r----- 1 root system 2, 1 Feb 11 2017 kmem
除了 root 管理员或属于 system 组成员外,所有用户都没有读取该文件的权限。由于在平时我们需要查看系统的进程状态,为了能够获取到进程的状态信息,可在用于查看系统进程状态的 ps
命令文件上增加 SGID 特殊权限位。查看 ps
命令文件的属性信息:
-r-xr-sr-x 1 bin system 59346 Feb 11 2017 ps
这样一来,由于 ps 命令被增加了 SGID 特殊权限位,所以当用户执行该命令时,也就临时获取到了 system 用户组的权限,从而可以顺利地读取设备文件了。
如果现在需要在一个部门内设置共享目录,让部门内的所有人员都能够读取目录中的内容,那么就可以创建部门共享目录后,在该目录上设置 SGID 特殊权限位。这样,部门内的任何人员在里面创建的任何文件都会归属于该目录的所属组,而不再是自己的基本用户组。此时,我们用到的就是 SGID的第二个功能,即在某个目录中创建的文件自动继承该目录的用户组(只可以对目录进行设置)。
drwxrwxrwx
—> drwxrwsrwx
drwxrw-rwx
—> drwxrwSrwx
执行命令:
chmod -R g+s DIR_NAME
【扩展命令】
chmod
:设置文件或目录的权限
chmod [optiom] 权限 FILE_NAME/DIR_NAME
chown
:设置文件或目录的所有者和所属组
chown [option] 所有者:所属组 FILE_NAME/DIR_NAME
<Tips> 针对目录进行操作时需要加上大写参数 -R
来表示递归操作,即对目录内所有的文件进行整体操作。
5.3.3 SBIT
SBIT(Sticky Bit)特殊权限位可确保用户只能删除自己的文件,而不能删除其他用户的文件。换句话说,当对某个目录设置了 SBIT 粘滞位权限后,那么该目录中的文件就只能被其所有者执行删除操作了。
与前面所讲的 SUID 和 SGID 权限显示方法不同,当目录被设置 SBIT 特殊权限位后,文件的其他人权限部分的 x 执行权限就会被替换成 t (原本有执行权限)或者 T(原本无执行权限)。
drwxrwxrwx
—> drwxrwxrwt
drwxrwxrw-
—> drwxrwxrwT
执行命令:
chmod -R o+t DIR_NAME
【补充】
chmod 1777 FILE_NAME/DIR_NAME
如果出现4个数字,那么第一个数字代表特殊权限。
SUID:4
SGID:2
SBIT:1
5.4 文件的隐藏属性
如果碰到明明权限充足但却无法删除某个文件的情况,或者仅能在日志文件中追加内容而不能修改或删除内容,意味着该文件具备隐藏权限。这在一定程度上阻止了黑客篡改系统日志的图谋,因此这种“奇怪”的文件也保障了 Linux 系统的安全性。
5.4.1 chattr 命令
用途:设置文件的隐藏权限。
格式:chattr [参数] 文件
如果想要把某个隐藏功能添加到文件上,则需要在命令后面追加“+参数”,如果想要把某个隐藏功能移出文件,则需要追加“-参数”。
参数 | 作用 |
---|---|
i | 无法对文件进行修改;若对目录设置了该参数,则仅能修改其中的子文件内容而不能新建或删除文件 |
a | 仅允许补充(追加)内容,无法覆盖/删除内容(Append Only) |
S | 文件内容在变更后立即同步到硬盘(sync) |
s | 彻底从硬盘中删除,不可恢复(用 0 填充原文件所在硬盘区域) |
A | 不再修改这个文件或目录的最后访问时间(atime) |
b | 不再修改文件或目录的存取时间 |
D | 检查压缩文件中的错误 |
d | 使用 dump 命令备份时忽略本文件/目录 |
c | 默认将文件或目录进行压缩 |
u | 当删除该文件后依然保留其在硬盘中的数据,方便日后恢复 |
t | 让文件系统支持尾部合并(tail-merging) |
X | 可以直接访问压缩文件中的内容 |
[redhat@linuxprobe ~]$ echo "for Test" > linuxprobe
[redhat@linuxprobe ~]$ chattr +a linuxprobe
[redhat@linuxprobe ~]$ rm linuxprobe
rm: remove regular file ‘linuxprobe’? y
rm: cannot remove ‘linuxprobe’: Operation not permitted
5.4.2 lsattr 命令
用途:显示文件的隐藏权限。
格式:lsattr [参数] 文件
一旦使用 lsattr
命令后,文件上被赋予的隐藏权限马上就会原形毕露。此时可以按照显示的隐藏权限的类型(字母),使用 chattr 命令将其去掉:
[redhat@linuxprobe ~]$ lsattr linuxp-----a---------- linuxprobe
[redhat@linuxprobe ~]$ chattr -a linuxprobe
[redhat@linuxprobe ~]$ lsattr linuxprobe
---------------- linuxprobe
[redhat@linuxprobe ~]$ rm linuxprobe
rm: remove regular file ‘linuxprobe’?
5.5 文件访问控制列表
前文讲解的一般权限、特殊权限、隐藏权限其实有一个共性—权限是针对某一类用户设置的。如果希望对某个指定的用户进行单独的权限控制,就需要用到文件的访问控制列表(ACL)了。
通俗来讲,基于普通文件或目录设置 ACL 其实就是针对指定的用户或用户组设置文件或目录的操作权限。另外,如果针对某个目录设置了 ACL,则目录中的文件会继承其 ACL;若针对文件设置了 ACL,则文件不再继承其所在目录的 ACL。
5.5.1 setfacl 命令
用途:管理文件的 ACL 规则
格式:setfacl [参数] 文件名称
针对目录文件需要使用 -R
递归参数;
针对普通文件则使用 -m
参数;
如果想要删除某个文件的 ACL,则可以使用 -b
参数。
示例:赋予普通用户 linuxprobe 查看/root的权限
[root@linuxprobe ~]# setfacl -Rm u:linuxprobe:rwx /root
[root@linuxprobe ~]# su - linuxprobe
Last login: Sat Mar 21 15:45:03 CST 2017 on pts/1
[linuxprobe@linuxprobe ~]$ cd /root
[linuxprobe@linuxprobe root]$ ls
anaconda-ks.cfg Downloads Pictures Public
[linuxprobe@linuxprobe root]$ cat anaconda-ks.cfg
[linuxprobe@linuxprobe root]$ exit
如何确认文件被设置了ACL呢?如果看到文件的权限最后一个点(.)变成了加号(+),这就意味着该文件已经设置了 ACL 。
[root@linuxprobe ~]# ls -ld /root
dr-xrwx---+ 14 root root 4096 May 4 2017 /root
5.5.2 getfacl 命令
用途:显示文件上设置的 ACL 信息。
格式:getfacl 文件名称
[root@linuxprobe ~]# getfacl /root
getfacl: Removing leading '/' from absolute path names
# file: root
# owner: root
# group: root
user::r-x
user:linuxprobe:rwx
group::r-x
mask::rwx
other::---
5.6 su 命令与 sudo 服务
su
命令可以解决切换用户身份的需求,使得当前用户在不退出登录的情况下,顺畅地切换到其他用户,比如从 root 管理员切换至普通用户:
[root@linuxprobe ~]# id
uid=0(root) gid=0(root) groups=0(root)
[root@linuxprobe ~]# su - linuxprobe
Last login: Wed Jan 4 01:17:25 EST 2017 on pts/0
[linuxprobe@linuxprobe ~]$ id
uid=1000(linuxprobe) gid=1000(linuxprobe) groups=1000(linuxprobe) context=unconfined_
u:unconfined_r:unconfined_t:s0-s0:c0.c1023
su
命令与用户名之间的减号(-),意味着完全切换到新的用户,即把环境变量信息也变更为新用户的相应信息,而不是保留原始的信息。强烈建议在切换用户身份时添加这个减号(-)。
sudo
命令用于给普通用户提供额外的权限来完成原本 root 管理员才能完成的任务,
格式:sudo [参数] 命令名称。
参数 | 作用 |
---|---|
-h | 列出帮助信息 |
-l | 列出当前用户可执行的命令 |
-u | 用户名或 UID 值 以指定的用户身份执行命令 |
-k | 清空密码的有效时间,下次执行 sudo 时需要再次进行密码验证 |
-b | 在后台执行指定的命令 |
-p | 更改询问密码的提示语 |
总结来说,sudo 命令具有如下功能:
- 限制用户执行指定的命令
- 记录用户执行的每一条命令
- 配置文件(/etc/sudoers)提供集中的用户管理、权限与主机等参数
- 验证密码的后 5 分钟内(默认值)无须再让用户再次验证密码
使用 sudo
命令提供的 visudo
命令可以配置用户权限。只有 root 管理员才可以使用visudo
命令编辑 sudo 服务的配置文件。切记一定要给出该命令的绝对路径,否则系统会识别不出来。
格式:
谁可以使用 允许使用的主机=(以谁的身份) 可执行命令的列表
[linuxprobe@linuxprobe ~]$ exit
logout
[root@linuxprobe ~]# whereis cat
cat: /usr/bin/cat /usr/share/man/man1/cat.1.gz /usr/share/man/man1p/cat.1p.gz
[root@linuxprobe ~]# visudo
96 ##
97 ## Allow root to run any commands anywhere
98 root ALL=(ALL) ALL
99 linuxprobe ALL=(ALL) /usr/bin/cat
[root@linuxprobe ~]# su - linuxprobe
Last login: Thu Sep 3 15:51:01 CST 2017 on pts/
[linuxprobe@linuxprobe ~]$ cat /etc/shadow
cat: /etc/shadow: Permission denied
[linuxprobe@linuxprobe ~]$ sudo cat /etc/shadow
root:$6$GV3UVtX4ZGg6ygA6$J9pBuPGUSgZslj83jyoI7ThJla9ZAULku3BcncAYF00Uwk6Sqc4E36
MnD1hLtlG9QadCpQCNVJs/5awHd0/pi1:16626:0:99999:7:::
bin:*:16141:0:99999:7:::
daemon:*:16141:0:99999:7:::
adm:*:16141:0:99999:7:::
lp:*:16141:0:99999:7:::
sync:*:16141:0:99999:7:::
shutdown:*:16141:0:99999:7:::
halt:*:16141:0:99999:7:::
mail:*:16141:0:99999:7:::
operator:*:16141:0:99999:7:::
games:*:16141:0:99999:7:::
ftp:*:16141:0:99999:7:::
nobody:*:16141:0:99999:7:::
………………省略部分文件内容………………
每次执行 sudo
命令后都会要求验证一下密码。虽然这个密码就是当前登录用户的密码,但是每次执行 sudo
命令都要输入一次密码其实也挺麻烦的,这时可以添加NOPASSWD 参数,使得用户执行 sudo
命令时不再需要密码验证:
[linuxprobe@linuxprobe ~]$ exit
logout
[root@linuxprobe ~]# whereis poweroff
poweroff: /usr/sbin/poweroff /usr/share/man/man8/poweroff.8.gz
[root@linuxprobe ~]# visudo
………………省略部分文件内容………………
96 ##
97 ## Allow root to run any commands anywhere
98 root ALL=(ALL) ALL
99 linuxprobe ALL=NOPASSWD: /usr/sbin/poweroff
………………省略部分文件内容………………