外观
权限与归属
Permission denied 几乎是新人第一周必遇到的错误。这一节把 ls -l 那串字符彻底拆开,再讲三个特殊位和 ACL。
一、读懂 ls -l
bash
ls -l /opt/apptext
-rwxr-x--- 1 app app 20480 Oct 27 21:20 start.sh
drwxr-xr-x 2 app app 4096 Oct 27 20:02 config
-rw-r--r-- 1 root root 1280 Oct 27 18:00 README.md
lrwxrwxrwx 1 app app 12 Oct 27 19:00 logs -> /data/app/logs逐位拆:
text
- rwx r-x --- 1 app app
│ │ │ │ │ │ │
│ │ │ │ │ │ └─ 所属组
│ │ │ │ │ └────── 属主
│ │ │ │ └────────── 硬链接数(目录表示子目录数+2)
│ │ │ └─────────────── 其他人 (other) 权限
│ │ └──────────────────── 所属组 (group) 权限
│ └───────────────────────── 属主 (user) 权限
└───────────────────────────── 类型:- 文件, d 目录, l 软链, s socket, p 管道, b/c 设备权限位含义:
| 位 | 文件 | 目录 |
|---|---|---|
r | 读内容 | 列出里面有哪些文件(ls) |
w | 改内容 | 在里面新建/删除/重命名文件 |
x | 执行 | 进入目录(cd)、访问里面的文件 |
目录没有 x 就什么都做不了
只有 r 没有 x 的目录:能 ls 看到文件名,但读不了文件内容、也 cd 不进去。这是"权限看起来给了却还是打不开"的常见原因。
二、chmod
数字法:
text
r = 4 w = 2 x = 1bash
chmod 644 app.conf # rw-r--r-- 普通文件
chmod 755 start.sh # rwxr-xr-x 可执行文件/目录
chmod 600 id_rsa # rw------- 私钥
chmod 640 app.env # rw-r----- 配置(组内可读)符号法:
bash
chmod u+x start.sh # 属主加执行
chmod g-w,o-rwx secret # 组去写、其他人全去
chmod a+r README.md # 所有人可读
chmod -R g+r /data/shared # 递归
chmod u=rwx,g=rx,o= dir # 精确设置X(大写)只给目录或已有执行位的文件加 x,适合递归:
bash
chmod -R a+rX /var/www # 文件保持原样,目录都加 x不要 chmod -R 777
777 意味着任何用户都能改、能删。把 web 目录设成 777,等于把上传目录变成提权入口(攻击者放一个 .php 进去直接执行)。
遇到权限问题正确的做法是:明确进程以哪个用户运行,然后只把该用户需要的权限给它。
三、chown
bash
chown app:app /opt/app -R
chown -R 10001:10001 /data/app
chgrp www-data /var/wwwchown user 只改属主,chown user:group 同时改。chown :group 只改组。
容器场景经常用 UID:
bash
docker run --rm myapp:1.0.0 idtext
uid=10001(app) gid=10001(app) groups=10001(app)bash
chown -R 10001:10001 /data/app/data四、umask:新文件的默认权限
bash
umasktext
0022规则:文件默认 666 减 umask,目录默认 777 减 umask。
| umask | 新文件 | 新目录 |
|---|---|---|
022 | 644 | 755 |
002 | 664 | 775 |
077 | 600 | 700 |
002 适合团队共享目录(同组可写),077 适合私密目录。
bash
# 临时
umask 002
# 永久(当前用户)
echo 'umask 002' >> ~/.bashrc五、三个特殊位
SUID(4)
bash
ls -l /usr/bin/passwdtext
-rwsr-xr-x 1 root root 32688 ... /usr/bin/passwd属主的 x 变成 s:任何用户执行它时,临时获得属主(root)的权限。passwd 靠这个改 /etc/shadow。
bash
chmod 4755 /path/to/binary # 加 SUID
chmod u-s /path/to/binary # 去 SUIDSUID 是提权面
给自定义脚本/程序加 SUID 前先想清楚:一旦程序有漏洞,攻击者直接拿到 root。查找系统里所有 SUID 文件:
bash
find / -perm -4000 -type f 2>/dev/nullSGID(2)
对文件:执行时临时获得属组权限(很少用)。 对目录:在目录里新建的文件,属组自动继承目录的组。
bash
chmod 2775 /data/shared
ls -ld /data/sharedtext
drwxrwsr-x 2 root devteam 4096 Oct 27 21:24 /data/shared团队共享目录的标准配置:chgrp devteam /data/shared && chmod 2775 /data/shared。
Sticky(1)
只对目录有效:目录里的文件只有属主(或 root)能删,即使其他人对该目录有写权限。
bash
ls -ld /tmptext
drwxrwxrwt 15 root root 4096 Oct 27 21:25 /tmp最后的 t 就是 sticky。/tmp 是 1777,人人都能建文件,但删不了别人的。
六、ACL:给单个用户开小灶
普通权限只有"属主/组/其他"三档。要给某个特定用户单独开权限,用 ACL。
bash
getfacl /data/report
setfacl -m u:zhangsan:rx /data/report
setfacl -m g:analysts:r /data/report/*text
# file: data/report
# owner: root
# group: root
user::rwx
user:zhangsan:r-x
group::r-x
group:analysts:r--
mask::r-x
other::r-x递归与默认 ACL:
bash
# 递归加(目录也要 x)
setfacl -R -m u:zhangsan:rX /data/report
# 默认 ACL:以后在这个目录里新建的文件自动带这些权限
setfacl -d -m u:zhangsan:rw /data/report
# 删除某条
setfacl -x u:zhangsan /data/report
# 删除全部 ACL
setfacl -b /data/reportgetfacl 输出里如果有个 +(ls -l 的权限串末尾),说明该文件有 ACL:
text
drwxr-x---+ 2 root root 4096 Oct 27 21:28 report备份恢复会丢 ACL
cp -a / tar 默认不带 ACL。要保留:
bash
cp -a --preserve=all src dst
tar --acls --xattrs -czf backup.tar.gz dir/
getfacl -R /data > acl-backup.txt # 单独备份 ACL
setfacl --restore=acl-backup.txt七、常见目录该给什么权限
| 场景 | 目录 | 文件 |
|---|---|---|
| Web 静态资源 | 755 | 644 |
| 上传目录(进程可写) | 755 属主为应用用户 | 进程创建的文件 644 |
| 团队共享(同组可写) | 2775 + 属组 | 664 |
| 临时交换目录 | 1777 | — |
| 私钥、密钥文件 | 700(目录) | 600 |
| 配置文件含密码 | 750 | 640 |
八、踩过的坑
| 现象 | 根因 | 处置 |
|---|---|---|
Permission denied 但权限看着是 r | 父目录缺 x | 给路径上每级目录补 x |
sudo 能跑、普通用户不行 | 文件属主/组不对 | chown 成运行用户 |
| 新文件组不对 | 缺 SGID | chmod 2775 目录 |
| 别人能删我的文件 | 目录是 777 无 sticky | chmod 1777 |
| 容器写不了挂载目录 | 容器 UID 与宿主不匹配 | chown 成容器内 UID |
chmod -R 777 后漏洞被利用 | 过度授权 | 收敛到最小权限 |
ACL 生效了但 cp 后丢了 | cp 不带 ACL | cp -a --preserve=all |
| SELinux 下仍报权限 | 安全上下文不对 | ls -Z、restorecon、挂载加 :z |