Linux 的安全性
每个进入 Linux 系统的用户会分配唯一的用户账户。用户权限是通过创建用户时分配的 用户ID(UID) 来追踪的,每个用户有唯一的 UID,但登录时用的是“登录名”,不是 UID。
在讨论文件权限前,先看看管理用户账户的文件和工具
/etc/passwd 文件
/etc/passwd 用于将用户的登录名匹配到对应的 UID. 下面是我的 /etc/passwd 文件的部分内容:
$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
每一行包含如下信息:
- 登录用户名
- 用户密码(隐藏为 x,真实密码在 /etc/shadow)
- UID
- GID
- 文字描述(称为备注字段)
- 用户 HOME 目录位置
- 用户默认 shell
第一行的 root 用户账户是 Linux 系统的管理员,固定分配的 UID 是 0。除了 root 外,系统会为各种功能创建不同的用户账户,称为 系统账户,是各种服务进程访问资源用的特殊账户。所有后台服务都需要用一个系统账户登录到 Linux 系统上。Linux 为系统账户预留了 500 以下的 UID 值。
/etc/shadow 文件
/etc/shadow 文件保存的密码和相关的设置,只有 root 用户才能访问。
$ sudo cat /etc/shadow
pi:$6$j.c1dy4MwJsxSw.Y$kRSXfoGsSt5UlXb12d6MqcSwxGx0Eh7zEIvQkdzoCu3Suc5FDfb74hl8GzHCllXS8wU0pTf5.yCslmPNT3SrD0:18629:0:99999:7:::
用户名后面的就是加密后的密码,除此之外,还有一些如“多少天后必修更改密码”的设置。
添加新用户
我们可以用 useradd
来添加新用户。一些发行版把 Linux 用户和组工具放在 /usr/sbin 目录下,需要手动将这个目录添加到 PATH 环境变量,或用绝对文件路径来使用这些工具。下面试着新建一个 test 账户
$ sudo /usr/sbin/useradd test
$ cat /etc/passwd | grep test
test:x:1001:1003::/home/test:/bin/sh
默认情况下 useradd 用默认值来创建新用户。默认值可以用 useradd -D
来查看:
$ /usr/sbin/useradd -D
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/sh
SKEL=/etc/skel
CREATE_MAIL_SPOOL=no
各行的意义如下:
- 添加到 GID=100 的公共组
- HOME 目录位于 /home/loginname
- 密码过期后不会禁用
- 未设置过期日期
- 默认 shell 为 /bin/sh
- 系统会将 /etc/skel 目录下的内容复制到 HOME 目录下
- 不会在 mail 目录下创建一个用于接收邮件的文件
想要改变默认值或默认行为,可以用命令行参数指定:
参数 |
描述 |
---|---|
|
给新用户添加备注 |
|
为主目录指定一个名字(如果不想用登录名作为主目录名的话) |
|
用YYYY-MM-DD格式指定一个账户过期的日期 |
|
指定这个账户密码过期后多少天这个账户被禁用; |
|
指定用户登录组的GID或组名 |
|
指定用户除登录组之外所属的一个或多个附加组 |
|
必须和 |
|
创建用户的HOME目录 |
|
不创建用户的HOME目录(当默认设置里要求创建时才使用这个选项) |
|
创建一个与用户登录名同名的新组 |
|
创建系统账户 |
|
为用户账户指定默认密码 |
|
指定默认的登录shell |
|
为账户指定唯一的UID |
删除用户
可以用 userdel
删除用户,但这只会删除 /etc/passwd 中的用户信息,并不会删除任何文件。如果加上 -r
参数,userdel
会删除用户的 HOME 目录和邮件目录,但系统上仍可能存在该用户的其他文件,这在有些环境中可能会造成问题。
$ sudo /usr/sbin/userdel test
$ cat /etc/passwd | grep test
修改用户
-
usermod
:用于修改 /etc/passwd 文件中的字段-
-c
修改备注字段 -
-e
修改过期日期 -
-g
修改默认的登录组 -
-l
修改登录名 -
-L
锁定账户,使之无法登录 -
-U
解除锁定 -
-p
修改密码
-
-
passwd
和chpasswd
- 单独的
passwd
会改自己的密码,如果是passwd 用户名
则会修改别人的密码(但只有 root 用户有权限) -
chpasswd
可以用于大量用户修改密码,它从输入读取 userid:passwd 形式的列表,然后为账户设置。
- 单独的
-
chsh
、chage
:用于修改默认 shell,后者用于修改
Linux 组
组权限允许多个用户对系统中的对象(文件、设备等)共享一组权限,这样能方便管理多个用户。每个组有唯一的组名和 GID。有些发行版会创建一个默认组,然后把新用户当作这个组的成员;有的则为每个用户单独创建一个组(比如 Ubuntu),这样更安全一点。
/etc/group 文件
/etc/group 文件中包含系统中每个组的信息。比如:
$ cat /etc/group
root:x:0:pi
daemon:x:1:
bin:x:2:
sys:x:3:
adm:x:4:pi
tty:x:5:
disk:x:6:
lp:x:7:
mail:x:8:
- 组名
- 组密码
- GID
- 属于该组的用户列表
系统账户的组通常是 500 以下的 GID,而用户组的 GID 则会从 500 开始分配。
创建组
groupadd
命令可以在系统上创建新组。和 useradd
一样,需要用绝对路径。
$ sudo /usr/sbin/groupadd test
$ tail /etc/group
libvirt:x:119:
libvirt-qemu:x:64055:libvirt-qemu
Debian-exim:x:120:
spi:x:1000:pi
i2c:x:1001:pi
gpio:x:1002:pi
cockpit-ws:x:121:
systemd-coredump:x:998:
jellyfin:x:122:
test:x:1003:
然后我们可以用 usermod
将用户添加到该组:
$ sudo /usr/sbin/usermod -G test pi
pi@raspbian:~$ tail /etc/group
libvirt:x:119:
libvirt-qemu:x:64055:libvirt-qemu
Debian-exim:x:120:
spi:x:1000:
i2c:x:1001:
gpio:x:1002:
cockpit-ws:x:121:
systemd-coredump:x:998:
jellyfin:x:122:
test:x:1003:pi
如果更改的是已登录系统账户的用户组,则需要重新登录后组关系的变更才生效。
另外,如果用的是 -g
选项,则会替换用户的默认组,-G
则是将该组添加到用户的属组的列表里。
修改组
用 groupmod
可以修改 GID(加 -g
选项)或组名(加 -n
选项)
理解文件权限
前面介绍 ls 命令时说过可以查看 Linux 系统上的文件、目录、权限:
$ ls -l
total 7772
drwxr-xr-x 7 pi sudo 4096 Feb 15 00:04 blog
drwxr-xr-x 6 pi root 4096 Feb 25 08:07 code
drwxr-xr-x 3 pi sudo 4096 Feb 16 00:04 frp
-rw-r--r-- 1 pi sudo 7926056 Feb 12 13:11 frp_0.35.1_linux_arm64.tar.gz
-rw-r--r-- 1 pi sudo 13226 Feb 12 12:42 install_nvm.sh
第一个字段就是描述文件和目录权限的编码,第一个字符代表了对象的类型:
-
-
代表文件 -
d
代表目录 -
l
代表链接 -
c
代表字符型目录 -
b
代表块设备 -
n
代表网络设备
之后有 3 组三字符的编码,每一组定义了 3 种访问权限权限:
-
r
代表可读 -
w
代表可写 -
x
代表可执行 -
-
代表没有对应权限
3 组权限分别对应 3 个安全级别:
- 对象的属主
- 对象的属组
- 系统的其他用户
比如,以输出的其中一行为例:
drwxr-xr-x 7 pi sudo 4096 Feb 15 00:04 blog
该目录有下面三组权限:
- rwx:目录的属主
- r-x:目录的属组
- r-x:系统上其他人
默认文件权限
可以用 umask 来查看或修改默新建文件的默认权限:
$ umask
0022
$ touch newfile
$ ls -al newfile
-rw-r--r-- 1 pi sudo 0 Feb 28 09:12 newfile
umask 输出的数字的第一位叫黏着位(sticky bit),我们后面再详细介绍。之后的三位对应着权限,对应方法如下:
每一组权限对应 8 进制的一位数,即:
权限 |
二进制值 |
八进制值 |
描述 |
---|---|---|---|
|
|
|
没有任何权限 |
|
|
|
只有执行权限 |
|
|
|
只有写入权限 |
|
|
|
有写入和执行权限 |
|
|
|
只有读取权限 |
|
|
|
有读取和执行权限 |
|
|
|
有读取和写入权限 |
|
|
|
有全部权限 |
umask 值是个掩码,把umask 值从对象的全权限值中减掉。对文件来说,全权限的值是666 (所有用户都有读和写的权限);而对目录来说,则是777 (所有用户都有读、写、执行权限)。所以在上例中,文件一开始的权限是666 ,减去umask 值022 之后,剩下的文件权限就成了644 。
在大多数Linux发行版中,umask 值通常会设置在/etc/profile启动文件中(参见第6章),不过有一些是设置在/etc/login.defs文件中的(如Ubuntu)。可以用umask 命令为默认umask 设置指定一个新值。
$ umask 026
$ touch newfile
$ ls -al newfile
-rw-r----- 1 pi sudo 0 Feb 28 09:24 newfile
改变安全性设置
改变权限
chmod 命令可以改变文件和目录的权限,格式:chmod options mode file
,比如:
$ ls -al newfile
-rw-r----- 1 pi sudo 0 Feb 28 09:24 newfile
$ chmod 760 newfile
$ ls -al newfile
-rwxrw---- 1 pi sudo 0 Feb 28 09:24 newfile
但用数字并不是那么直观,我们一般用下面这种格式:
chmod [ugoa][+-=][rwxXstugo] file
第一个方括号内的字符定义了权限作用的对象:
- u - user 用户
- g - group 组
- o - others 其他
- a - all 上面所有
第二组字符表示需要增加权限(+)、移除权限(-)、还是设置成后面的值(=)
第三组字符表示权限,除了读(r)、写(w)、执行(x)外,还有以下几项:
- X :如果对象是目录或者它已有执行权限,赋予执行权限。
- s :运行时重新设置UID或GID。
- t :保留文件或目录。
- u :将权限设置为跟属主一样。
- g :将权限设置为跟属组一样。
- o :将权限设置为跟其他用户一样。
示例:
$ chmod o+r newfile
$ ls -lF newfile
-rwxrw-r-- 1 pi sudo 0 Feb 28 09:24 newfile*
$ chmod u-x newfile
$ ls -lF newfile
-rw-rw-r-- 1 pi sudo 0 Feb 28 09:24 newfile
chmod 支持递归(加 -R
选项)和通配符。
改变所属关系
chown 命令可以改变属主/属组,chgrp 命令可以改变默认属组。
chown 的格式如下:
$ chown options owner[.group] file
只有 root 用户能够改变文件的属主。任何属主都可以改变文件的属组,但前提是属主必须是原属组和目标属组的成员。
示例:
$ sudo chown root.root newfile
$ ls -lF newfile
-rw-rw-r-- 1 root root 0 Feb 28 09:24 newfile
$ sudo chown .sudo newfile
$ ls -lF newfile
-rw-rw-r-- 1 root sudo 0 Feb 28 09:24 newfile