特殊权限与提权(su / sudo)
一句话总结:rwx 管“能不能”,特殊权限管“以谁的身份、能否删别人的文件”,su/sudo 管“怎么换身份”。
适用:Rocky Linux / CentOS 9。基础 rwx 见 10_用户组与权限.md,本篇讲进阶部分。
一、先回顾:权限怎么生效
1.1 三组权限 + 匹配顺序
ls -l 的 9 位权限,3 位一组:
-rwxr-xr--. 1 root group1 31457280 4月 16 14:21 /tmp/a.txt
│└┬┘└┬┘└┬┘
│ │ │ └── o 其他人:r--
│ │ └───── g 属组:r-x
│ └──────── u 属主:rwx
└────────── 文件类型
进程访问文件时,内核按 u → g → o 顺序匹配一次,命中即停,不取并集。
例:文件
rwx------ root root,用户 jack 在 root 组里,他仍然只能按“其他人”看(没有权限)。
1.2 权限对普通文件的意义
| 权限 | 含义 | 例子 |
|---|---|---|
r |
读取文件内容 | cat 1.txt |
w |
修改文件内容(不包含删除文件本身) | echo 111 >> 1.txt |
x |
把文件当命令执行 | ./script.sh |
执行的两类文件:
- 二进制程序(
/usr/bin/ls):只需要x权限就能跑; - 脚本文件(内容是文本,靠解释器执行):需要
r+x,因为解释器要先读内容再执行。
能不能删除一个文件,不看文件自己的
w,而看所在目录的w——这是最容易被忽略的一点。
1.3 权限对目录的意义
| 权限 | 对目录的含义 | 命令 |
|---|---|---|
r |
能列出目录里的文件名 | ls /dir |
w |
能在目录里创建、删除、移动、改名文件 | touch /dir/a、rm /dir/a |
x |
能进入目录,访问里面的文件 | cd /dir、cat /dir/a |
- 只有
r没有x:ls看得到名字,但cat里面的文件会 Permission denied。 - 只有
x没有r:能cd进去、能访问已知文件名的文件,但ls列不出来。 - 有
w没有x:能建文件却进不去,实际很难用。
1.4 路径沿途的 x 权限(重点)
访问 /a/b/c/1.txt 时:
- 进程用户要对
/、/a、/a/b、/a/b/c每一级目录都有x; - 再对
1.txt本身有对应权限(读/写/执行)。
常见故障:文件权限明明是
777,但cat /a/b/c/1.txt还是 Permission denied——因为中间某个目录缺x。
二、umask:新建文件的默认权限
2.1 计算规则
- 文件系统默认上限:普通文件
666(默认不给执行位),目录777; - 实际权限 = 默认上限 按位与上 umask 的取反,口算时用减法更直观:
- 文件:
666 - umask - 目录:
777 - umask
root 默认 umask 是 022,所以:
文件 666 - 022 = 644 (rw-r--r--)
目录 777 - 022 = 755 (rwxr-xr-x)
2.2 对照表
| umask | 新建文件 | 新建目录 |
|---|---|---|
| 022 | 644 | 755 |
| 002 | 664 | 775 |
| 027 | 640 | 750 |
| 077 | 600 | 700 |
| 066 | 600 | 711 |
| 023 | 644 | 754 |
注意 umask 是八进制,且减法只对每一位有效;
777 & ~066 = 711这种用“按位与”算更保险。
2.3 查看与设置
umask # 查看当前值
umask -S # 用 rwx 形式显示
umask 027 # 临时修改,只对当前 shell 生效
永久生效:
| 位置 | 作用范围 |
|---|---|
/etc/profile |
全局,登录时 |
~/.bashrc |
当前用户,每次开 shell |
/etc/login.defs 的 UMASK |
新建用户的默认 umask(useradd 时也会用) |
三、特殊权限:SUID / SGID / Sticky
这三个权限占 ls -l 输出的第 4、7、10 位(原本是 x 的位置)。
| 特殊权限 | 数字 | 作用对象 | 效果 |
|---|---|---|---|
| SUID | 4 | 可执行文件 | 程序运行时以文件属主的身份运行 |
| SGID | 2 | 目录(也可执行文件) | 目录里新建的文件/目录继承目录的属组;可执行文件以文件属组身份运行 |
| Sticky | 1 | 目录 | 目录里的文件只有属主和 root 能删除/改名 |
3.1 SUID(Set User ID)
chmod u+s /usr/bin/passwd
chmod 4755 /usr/bin/passwd
ls -l /usr/bin/passwd
# -rwsr-xr-x. 1 root root ... /usr/bin/passwd
典型例子:passwd 的属主是 root,普通用户执行它时临时获得 root 身份,才能去改 /etc/shadow。
- 显示为
s(原位置有 x)或S(原位置没有 x,说明配置有误); - 只对可执行文件有意义,给普通文本加 SUID 没用;
- 风险最高:如果给
bash、vim这类程序加 SUID,等于给了所有人 root shell。
find / -perm -4000 -type f 2>/dev/null # 排查系统里所有 SUID 程序
3.2 SGID(Set Group ID)
对目录(最常用):目录里新建的文件和子目录,属组自动继承该目录的属组,而不是创建者的主组。
chmod g+s /aaa
chmod 2775 /aaa
ls -ld /aaa
# drwxrwsr-x. root it ... /aaa
部门共享目录的标准做法:
chgrp it /share+chmod 2770 /share,这样组员新建的文件都自动属于it组,其他人也能按组权限访问。
对可执行文件:程序运行时以文件属组的身份运行(用得少)。
3.3 Sticky(粘滞位)
chmod o+t /share
chmod 1777 /share
ls -ld /tmp
# drwxrwxrwt. 20 root root ... /tmp
效果:目录里人人可写,但只有文件属主和 root 能删除或改名。
/tmp 就是典型:所有人能建文件,但删不了别人的文件。
3.4 数字表示与识别
chmod 4755 file # SUID + 755
chmod 2755 dir # SGID + 755
chmod 1777 dir # Sticky + 777
chmod 7755 file # 同时有 SUID+SGID+Sticky(几乎不用)
| 显示 | 含义 |
|---|---|
rws |
有 x,且设置了 SUID |
rwS |
没有 x,却设置了 SUID(无效配置) |
rws(属组位) |
有 x,且设置了 SGID |
rwt(其他人位) |
有 x,且设置了 Sticky |
rwT |
没有 x,却设置了 Sticky |
3.5 安全提醒
- SUID 程序越少越安全,定期用
find / -perm -4000审计; - 不要给 shell、编辑器、解释器加 SUID;
- 共享目录优先用 SGID + 组权限,而不是
777。
四、su:切换用户
4.1 两种写法
| 命令 | 类型 | 环境变量 |
|---|---|---|
su - egon(或 su -l) |
登录 shell | 重新加载目标用户完整环境,家目录切到 /home/egon |
su egon |
非登录 shell | 只切换身份,环境变量、当前目录大多保留 |
su - egon # 推荐:完整切换
su egon # 临时切身份,环境还是原来的
su - egon -c "id" # 切换后执行一条命令再退出
su -c "systemctl restart nginx" # root 用,切到 root 执行
su默认切到 root,需要目标用户的密码;root 切到普通用户不需要密码。
4.2 登录 / 非登录 shell 加载哪些配置文件
登录 shell(su - user、ssh user@host、tty 登录)依次加载:
/etc/profile
└─ /etc/profile.d/*.sh
~/.bash_profile
└─ ~/.bashrc
└─ /etc/bashrc
└─ /etc/profile.d/*.sh(RHEL 的 /etc/bashrc 会再跑一遍)
非登录 shell(su user、在已有 shell 里再开一个 bash):
~/.bashrc
└─ /etc/bashrc
└─ /etc/profile.d/*.sh
结论:想在登录时就生效的(PATH、LANG)写
/etc/profile或~/.bash_profile;想每次开 shell 都生效的(别名、函数、提示符)写~/.bashrc。
CentOS 9 里登录流程中/etc/bashrc可能被执行两次,所以脚本里别写有副作用的命令。
4.3 把命令加进 PATH
# 临时
export PATH="$PATH:/usr/local/nginx/sbin"
# 永久:写进 ~/.bash_profile 或 /etc/profile.d/nginx.sh
echo 'export PATH=$PATH:/usr/local/nginx/sbin' > /etc/profile.d/nginx.sh
source /etc/profile.d/nginx.sh
五、sudo:临时提权
5.1 它解决什么问题
- 不用知道 root 密码:普通用户用自己的密码认证;
- 按命令授权:只允许执行指定的几条命令;
- 有审计:执行记录写进
/var/log/secure; - 可撤销:改配置立即生效,不用改 root 密码。
sudo systemctl restart nginx # 用普通用户身份,临时以 root 执行这一条
sudo -l # 查看自己被授权了哪些命令
sudo -u www-data whoami # 以指定用户身份执行
sudo -i # 相当于 su -,进入 root 的登录 shell
5.2 /etc/sudoers 语法
用户 主机=(运行身份) 命令
| 字段 | 说明 | 例子 |
|---|---|---|
| 用户 | 用户名或用 %组名 |
egon、%wheel、%it |
| 主机 | 允许从哪台机器执行,ALL 表示任意 |
ALL |
| 运行身份 | 以谁的身份执行,ALL 或 (root) |
(ALL) |
| 命令 | 允许执行的命令,写绝对路径,可带参数 | /usr/bin/systemctl restart nginx |
root ALL=(ALL) ALL
%wheel ALL=(ALL) ALL
egon ALL=(ALL) ALL
lisi ALL=(root) /usr/bin/systemctl restart nginx
wangwu ALL=(ALL) NOPASSWD: /usr/bin/systemctl status nginx
NOPASSWD:表示执行时不再输密码;- 命令可以用通配符,但授权越具体越安全;
- 多个命令用逗号分隔;
- 还支持别名:
User_Alias ADMINS = egon, lisi
Cmnd_Alias WEB = /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx
ADMINS ALL=(root) WEB
5.3 两种修改方式
| 方式 | 说明 |
|---|---|
visudo |
推荐:编辑 /etc/sudoers,保存时自动检查语法,语法错不让你保存 |
vi /etc/sudoers |
直接改,容易写错;改完必须 visudo -c 检查 |
visudo # 打开编辑器
visudo -c # 只检查语法
EDITOR=vim visudo # 指定用 vim 编辑
visudo默认调起 vi。vi 有两种模式:命令模式(按键当命令)和编辑模式(i/a/o进入,可以输入文字),保存退出是Esc→:wq。不熟悉的话先把EDITOR设成nano或vim。
图:vi 的命令模式与编辑模式切换
5.4 企业里的推荐做法
- 用组授权:
%wheel ALL=(ALL) ALL,需要提权的人加进 wheel 组:bash usermod -aG wheel egon - 细分权限:运维只给重启服务的命令,DBA 只给数据库相关命令;
- 用 drop-in 文件:不直接改主配置,新建
/etc/sudoers.d/web:text %web ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx文件权限必须440,否则 sudo 会忽略或报错; - 改完检查:
visudo -c; - 定期审计:
sudo -l -U 用户名、查/var/log/secure里的sudo记录。
5.5 常见报错
| 报错 | 原因 |
|---|---|
xxx is not in the sudoers file |
没授权,或组没写对 |
sorry, you must have a tty to run sudo |
配置了 Defaults requiretty |
sudo: parse error in /etc/sudoers |
语法错误,用 visudo -c 定位 |
| 输入密码后仍拒绝 | 命令路径写错(必须绝对路径),或参数不匹配 |
速查表
# 特殊权限
chmod u+s file; chmod 4755 file # SUID
chmod g+s dir; chmod 2775 dir # SGID
chmod o+t dir; chmod 1777 dir # Sticky
find / -perm -4000 -type f 2>/dev/null # 审计 SUID
# umask
umask; umask -S; umask 027
umask 022 # 文件 644 / 目录 755
# su
su - egon; su egon; su -c "id"
# 登录 shell:/etc/profile -> profile.d -> ~/.bash_profile -> ~/.bashrc -> /etc/bashrc
# 非登录:~/.bashrc -> /etc/bashrc -> profile.d
# sudo
visudo; visudo -c
sudo -l; sudo -u user cmd; sudo -i
usermod -aG wheel egon
常见坑
- 以为文件有
w就能删——删除看的是目录的w。 - 文件权限 777 却打不开——路径沿途目录缺
x。 - 给脚本只加
x不加r,执行报错,因为解释器读不了内容。 chmod 4755和chmod 755只差一个数字,安全等级差很多,别手滑。- SGID 加在目录上才有“继承属组”的效果,加在普通文件上没意义。
- umask 是八进制减法,
027不是27,写错会得到奇怪权限。 su egon不加载目标用户环境,PATH 还是原来的,容易“命令找不到”。sudo授权命令必须写绝对路径,写systemctl会不生效。/etc/sudoers.d/下的文件权限要440,否则 sudo 拒绝加载。- 改 sudoers 不用
visudo,语法错了可能导致所有人都无法 sudo。
练习(16 题)
只允许 lisi 重启 nginx 且不用输密码,写出配置行。
查看答案
属主 rwx(读写执行),属组 r-x(读和执行),其他人 r--(只读)。
修改 sudoers 的推荐命令是什么?改完如何检查语法?
查看答案
需要所在目录的
w和x。文件名是目录里的一条记录,删除就是删记录,和文件自身的w无关。
为什么 cat /a/b/c/1.txt 会要求 /a、/a/b、/a/b/c 都有 x?
查看答案
目录的
x是“进入/穿越”权限;路径每一级都要能穿过,才能到达最终文件,再判断文件本身的权限。
二进制程序和 shell 脚本执行时对权限的要求有什么不同?
查看答案
二进制程序只需要
x;脚本文件需要r+x,因为解释器要先读取脚本内容才能执行。
umask 为 027 时,新建文件和目录的默认权限分别是多少?
查看答案
文件
666-027=640(rw-r-----),目录777-027=750(rwxr-x---)。
写出查看和临时设置 umask 的命令。
查看答案
umask
umask 027
SUID、SGID、Sticky 的数字代号分别是什么?
查看答案
SUID=4,SGID=2,Sticky=1。
给 /usr/bin/passwd 加 SUID,写出两条等价命令。
查看答案
chmod u+s /usr/bin/passwd
chmod 4755 /usr/bin/passwd
为什么 passwd 需要 SUID?不加会怎样?
查看答案
passwd要改/etc/shadow,普通用户没有写权限。加 SUID 后,执行 passwd 的进程临时以文件属主 root 的身份运行,才能改 shadow。不加 SUID,普通用户改密码会失败。
SGID 加在目录上有什么效果?举一个企业场景。
查看答案
目录里新建的文件和子目录自动继承该目录的属组。场景:部门共享目录
chgrp it /share+chmod 2770 /share,组员新建的文件都属于 it 组,方便组内协作。
Sticky 位的作用是什么?/tmp 的权限是多少?
查看答案
目录里的文件只有属主和 root 能删除或改名,其他人即使有
w也不能删别人的文件。/tmp是1777(drwxrwxrwt)。
ls -l 权限位出现 rws、rwS、rwt 分别代表什么?
查看答案
rws:有 x,且设置了 SUID;rwS:没有 x 却设置了 SUID(无效);rwt:有 x,且设置了 Sticky。
登录 shell 和非登录 shell 加载的配置文件有什么不同?
查看答案
登录 shell 依次读
/etc/profile、/etc/profile.d/*.sh、~/.bash_profile、~/.bashrc、/etc/bashrc;非登录 shell 只读~/.bashrc、/etc/bashrc(RHEL 的 bashrc 会再跑 profile.d)。所以 PATH 类配置写 profile,别名写 bashrc。
su - egon 和 su egon 的区别是什么?
查看答案
su - egon是登录 shell,重新加载目标用户完整环境、切到家目录;su egon是非登录 shell,只换身份,环境和当前目录大多保留。
把 /usr/local/nginx/sbin 永久加入 PATH,写出一种做法。
查看答案
echo 'export PATH=$PATH:/usr/local/nginx/sbin' > /etc/profile.d/nginx.sh
source /etc/profile.d/nginx.sh
> 写到 `~/.bash_profile` 也可以,但只对单个用户生效。
**16.**
> 用户 egon 在任意主机上,可以以任意身份(含 root)执行任意命令。
**17.**
```text
lisi ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx
18.
visudo
visudo -c
visudo保存时自动校验,-c只检查不修改;也可以写到/etc/sudoers.d/下,权限设为 440。
/etc/sudoers 中一行 egon ALL=(ALL) ALL 表示什么?
查看答案
(暂无答案)