Skip to content

Chapter 1 Linux 系统安全基础

1 Users and Groups

1. 1 Users

Linux 为每个用户分配一个唯一的 UID(User ID),系统通过 UID 识别用户,而不是只依赖用户名。

  • 用户信息保存在 /etc/passwd 中
  • root 用户的特殊 UID 是 0,系统通常依据 UID 判断其权限,因此 UID 为 0 的账户具有 root 级别权限
  • 用户的主组由 /etc/passwd 中的 GID 字段指定

使用 id 查看当前用户的 UID、GID 和所属用户组

seed@VM:~$ id
uid=1000(seed) gid=1000(seed) groups=1000(seed)

root@VM:~# id
uid=0(root) gid=0(root) groups=0(root)

添加用户有两种方式:

  • 直接修改 /etc/passwd,但还需要同时处理用户组、主目录、密码和登录 shell 等信息
  • 使用 adduser 命令,由系统完成用户创建相关工作

切换到其他用户

seed@VM:~$ su bob
Password:
bob@VM:/home/seed$

1. 2 Groups

Group(用户组) 表示一组用户,主要用于按照组分配访问权限。一个用户可以属于多个用户组。用户的主组(primary group)记录在 /etc/passwd 的 GID 字段中,其他附加组通常记录在 /etc/group 中。

Which group does a user belong to?

可以使用 groups、id 或查询 /etc/group:

groups 命令直接列出当前用户所属全部组
seed@VM:~$ groups
seed adm sudo plugdev lpadmin lxd docker
id 命令同时输出 UID、主组 GID、所有组(ID + 名字)
seed@VM:~$ id
uid=1000(seed) gid=1000(seed) groups=1000(seed),4(adm),27(sudo),46(plugdev),120(lpadmin),131(lxd),136(docker)
grep 命令筛选出包含 seed 的组记录
seed@VM:~$ grep seed /etc/group
adm:x:4:syslog,seed
sudo:x:27:seed
plugdev:x:46:seed
lpadmin:x:120:seed
lxd:x:131:seed
seed:x:1000:
docker:x:136:seed

创建用户组并把用户加入用户组

创建名为 alpha 的用户组
$ sudo groupadd alpha
把用户加入 alpha 这一附加组
$ sudo usermod -a -G alpha seed
$ sudo usermod -a -G alpha bob
  • -a 表示 append,和 -G 一起使用时追加用户组,省略 -a 可能覆盖用户原有的附加组

2 Permissions and Access Control

文件权限 目录权限
r(read) 查看文件内容 列出目录内容,例如使用 ls
w(write) 修改文件内容 在目录中创建文件和子目录
x(execute) 执行或运行文件 进入目录,例如使用 cd

2. 1 File Permissions

权限也可以用八进制表示

权限位 r、w、x、- 对应的数值依次为 4、2、1、0,每三个权限位对应一个八进制数字,例如 rwxr-xr-x = 755。

使用 chmod 修改权限
chmod u+x file       # 为 owner 增加执行权限
chmod g-w file       # 删除 group 的写权限
chmod o-r file       # 删除 other 的读权限
chmod 755 file       # 直接使用八进制设置权限

2. 2 Default File Permissions

umask 决定新建文件或目录的默认权限,新建对象的最终权限由初始权限和 umask 共同决定。

\[ \text{Final permission} = \text{Initial permission} \mathbin{\&} \mathop{\sim}\text{umask} \]

普通文件的初始权限通常为 0666,不包含执行权限,目录的初始权限通常为 0777。umask 中为 1 的位会屏蔽对应的默认权限。

示例
$ umask
0002
$ touch t1

$ umask 0022
$ touch t2

$ umask 0777
$ touch t3

对普通文件,初始权限为 0666:

Initial  (0666)  rw- rw- rw-
                 110 110 110
umask    (0022)  000 010 010
--------------------------------
Final              110 100 100
                   rw- r-- r--

最终结果:

$ ls -l t*
-rw-rw-r-- 1 seed seed 0 Feb 6 16:23 t1
-rw-r--r-- 1 seed seed 0 Feb 6 16:24 t2
---------- 1 seed seed 0 Feb 6 16:24 t3

2. 3 Access Control List

ACL(Access Control List,访问控制列表) 提供比传统 owner-group-other 模型更细粒度的权限控制,可以为单独的用户或用户组分配权限,也可以与传统权限模型共存,适合需要对多个特定用户或用户组单独授权的场景。

getfacl 命令查看 ACL 权限

$ getfacl example
# file: example
# owner: seed
# group: seed
user::rw-
group::rw-
other::r--

setfacl 命令设置 ACL 权限

setfacl {-m, -x} {u, g}:<name>:[r, w, x] <file, directory>
  • -m(modify):添加或修改 ACL 条目
  • -x(remove):删除 ACL 条目
  • u:<name>:指定用户
  • g:<name>:指定用户组
示例
给用户 alice 单独设置对 example 文件只读权限
$ setfacl -m u:alice:r-- example
给 faculty 组单独设置 example 文件读写权限
$ setfacl -m g:faculty:rw- example
查看 ACL 权限
$ getfacl example
# file: example
# owner: seed
# group: seed
user::rw-
user:alice:r--
group::rw-
group:faculty:rw-
mask::rw-
other::r--
  • mask 表示 ACL 中命名用户、命名用户组以及文件拥有组能够获得的最大有效权限
  • 文件拥有者和 other 不受 mask 限制
  • 文件具有扩展 ACL 时,ls -l 的权限字段末尾会出现 +
-rw-rw-r--+ 1 seed seed 1050 Feb 7 10:57 example

3 Running Commands with Privilege

Why Need Privilege Mechanisms?

Linux 中有些操作需要超级用户权限,常见的三种机制是:

  • sudo:以授权方式运行需要特权的命令。
  • set-uid programs:通过程序文件的 SUID 位临时使用文件拥有者身份。
  • POSIX capabilities:把超级用户权限拆分为更细粒度的能力集合。

3. 1 Using sudo

sudo 是 Super-user Do 的缩写,用于以超级用户身份运行命令:

sudo <command>

用户必须先获得授权,授权规则通常写在 /etc/sudoers 中。Ubuntu 中的典型配置为:

In /etc/sudoers
%sudo ALL=(ALL:ALL) ALL

其中 %sudo 表示 sudo 用户组,而不是名为 sudo 的单个用户。该规则允许 sudo 组中的用户以其他用户和用户组身份运行命令。

用户是否属于 sudo 组可以在 /etc/group 中看到:

In /etc/group
sudo:x:27:seed

这里表示 seed 属于 GID 为 27 的 sudo 组,因此可以使用 sudo。

3. 2 Getting Root Shell

在 Ubuntu 20.04 中,root 用户账户默认被锁定,不能直接登录 root 账户。

通过已有的 sudo 权限获得 root shell

sudo -s
sudo bash
sudo su
不建议长期使用 root shell

root shell 中执行的每条命令都具有最高权限,出错或误操作的影响范围很大。通常应当只对需要特权的单条命令使用 sudo,而不是进入 root shell 后一直工作。

3. 3 Running Command Using Another User

sudo 默认以 root 身份执行命令,也可以通过 -u 指定其他用户。

以 bob 身份运行 id

$ sudo -u bob id
uid=1001(bob) gid=1001(bob) groups=1001(bob),1004(alpha)

4 Authentication

4. 1 Authentication Methods

Authentication(认证) 是验证用户身份的过程,即确认发起请求的主体确实是其声称的用户。

常见认证因素类型 含义 示例
Something you know 用户知道的信息 password
Something you have 用户持有的物品 ID card
Something you are or do 用户的生物特征或行为特征 fingerprint

多因素认证(Multi-factor authentication) 同时使用两种或更多不同类型的认证因素,例如密码加身份证明设备,不能只把同一种因素重复使用当作多因素认证。

4. 2 The Password File

Linux 的 /etc/passwd 文件保存每个用户账户的基本信息。/etc/passwd 每行对应一个账户,字段格式为:

username:password:UID:GID:GECOS:home directory:login shell
各字段含义
字段 含义
username 用户名
x 密码占位符,实际密码信息保存在
UID 用户 ID,一般新建普通用户 uid 从 1000 开始
GID 用户的主组 ID
GECOS 用户描述、姓名等信息
home directory 用户的主目录
login shell 登录后启动的 shell
示例
root:x:0:0:root:/root:/bin/bash
seed:x:1000:1000:SEED,,,:/home/seed:/bin/bash
bob:x:1001:1001:Bob,,,:/home/bob:/bin/bash
alice:x:1002:1003:Alice,,,:/home/alice:/bin/bash

4. 3 First Command After Login

登录成功后,登录程序会执行 /etc/passwd 每行最后一个字段指定的 shell。这个 shell 通常是用户登录后执行的第一个命令程序,例如 /bin/bash。

系统账户通常不允许交互式登录,会把登录 shell 设置为特殊程序,例如 /usr/sbin/nologin 和 /bin/false。

示例
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,,:/var/lib/tpm:/bin/false
gdm:x:125:130:Gnome Display Manager:/var/lib/gdm3:/bin/false

当目标用户的 shell 是 /usr/sbin/nologin 或 /bin/false 时,切换到该用户会失败:

$ sudo su bin
This account is currently not available.

4. 4 The Shadow File

Why not use /etc/password anymore?

/etc/passwd 通常需要对所有用户可读。如果把密码哈希放在这里,任何普通用户都可以收集哈希并进行离线破解。

/etc/shadow 每行的基本结构为:

login:encrypted password:last change:min:max:warn:inactive:expire:reserved
各字段含义
字段 含义
login 用户名
encrypted password 密码哈希及其算法、salt
last change 上次修改密码的日期,通常表示为自 1970-01-01 起的天数
min 修改密码后至少经过多少天才能再次修改
max 密码最多有效多少天
warn 密码过期前提前警告的天数
inactive 密码过期后账户保持可用的天数
expire 账户过期日期
reserved 保留字段

4. 5 The Purpose of Salt

密码字段通常包含 $6$<salt>$<password hash> 的结构,其中 salt 可以提高暴力破解的成本、增加字典攻击的难度、破坏预先计算的 rainbow table,使使用同一个密码的不同账户得到不同的密码哈希。

示例
seed:$6$n8DimvsbIgUO0xbD$YZ0h1EA...(omitted)...wFd0:18590:0:
alice:$6$.1CMC.../8Qzl$QhfhId...(omitted)...Sga.:18664:0:
bob:$6$NOLhqomO3yNwYFsZ$K.Q1/KnP...(omitted)...b8v.:18664:0:
  • $6$ 表示所使用的哈希算法标识,在常见 Linux 配置中代表 SHA-512
  • salt 是为该账户随机生成的盐值
  • 最后一段是使用 salt 计算得到的密码哈希

4. 6 Locking Account

可以在密码字段放入无效值来锁定账户。例如:

root:!:18590:0:99999:7:::

密码字段中的 ! 不是有效的密码哈希,因此通过密码认证无法登录该账户。

在 Ubuntu 中,root 账户默认处于锁定状态,用户不能直接用 root 密码登录,但已授权的普通用户仍然可以通过 sudo 执行需要 root 权限的命令。