主题
界面
主题
《Linux 常用命令与部署》 用了 ls -l,输出里有这么一串:
-rw-r--r-- 1 testuser 1000 6494 Sep 21 16:26 README.md本节就是把这串"天书"讲清楚 ✓
它为什么重要:
"服务起不来,报 Permission denied"
"我明明有文件,为什么读不出来"
"同事能改我的配置文件?"
↓
都是权限问题完成本节后,你应该能够:
ls -l 的每一列(尤其权限位)★;chmod / chown;umask 与新建文件默认权限的关系;sudo 的意义;chmod 777 是危险的" ★★★;ls -l、cd、pwd 吗?(《Linux 常用命令与部署》)权限是 Linux 安全的第一道防线 ✓
三个真实场景:
| 场景 | 权限怎么起作用 |
|---|---|
| 部署的应用不该能删系统文件 | 用专用用户(如 deploy)跑,它没权限 ✓ |
| 配置文件里有数据库密码 | 文件权限设为 600(只有属主能读)★ |
| 多个开发共用一个部署账号 | 用"组"管理,避免互相改坏 ✓ |
它也是"最小权限原则"在操作系统层的落地:
一个进程只应该拥有"完成工作所必需"的权限 ✓
这与 《Filter、Listener 与会话管理》 的"默认拒绝 + 白名单"、《Git Flow 与团队协作》 的"分支保护"是同一条原则 ✓
ls -l 的每一列 实测输出:
-rw-r--r-- 1 testuser 1000 6494 Sep 21 16:26 README.md| 位置 | 值 | 含义 |
|---|---|---|
| ① 第 1 字符 | - | 文件类型(- 普通文件、d 目录、l 软链接)✓ |
| ② 第 2~10 字符 | rw-r--r-- | 权限(本节重点)★ |
| ③ 硬链接数 | 1 | — |
| ④ 属主 | testuser | 谁拥有它 ✓ |
| ⑤ 属组 | 1000 | 属于哪个组 ✓ |
| ⑥ 大小 | 6494 | 字节 |
| ⑦ 修改时间 | Sep 21 16:26 | ✓ |
| ⑧ 文件名 | README.md | ✓ |
文件类型(第 1 个字符):
| 字符 | 类型 |
|---|---|
- | 普通文件 ✓ |
d | 目录 ★ |
l | 软链接(lrwxrwxrwx,后面会显示 -> 目标)✓ |
c / b | 字符设备 / 块设备 |
s / p | socket / 管道 |
-rw-r--r--
│└┬┘└┬┘└┬┘
│ │ │ └── other(其他人)
│ │ └───── group(属组)
│ └──────── user(属主)
└────────── 文件类型三类权限:
| 字符 | 含义 | 对文件 | 对目录 ★ |
|---|---|---|---|
r(4) | 读 | 读内容 | 列出目录内容(ls) |
w(2) | 写 | 改内容 | 在目录里增删文件 |
x(1) | 执行 | 当程序运行 | 进入目录(cd)★★ |
★ 目录的 x 是关键(这一条最容易搞错):
对目录来说,"执行"="能否
cd进去" ✓一个目录如果没有
x,即使有r,你也只能"看到文件名",不能读文件内容、不能进入 ✗
实测体会:
mkdir demo && echo hi > demo/a.txt
chmod 600 demo # 只有 rw,没有 x
ls demo # ✓ 能列出 a.txt(因为有 r)
cat demo/a.txt # ✗ Permission denied(没有 x,进不去)
cd demo # ✗ Permission denied这解释了一个常见困惑:"我能看到文件名,却打不开它" —— 因为目录缺 x ✓
每个三位的组,用 r=4 / w=2 / x=1 相加 ✓
| 权限 | 计算 | 数字 |
|---|---|---|
rw- | 4+2+0 | 6 |
r-x | 4+0+1 | 5 |
rwx | 4+2+1 | 7 |
r-- | 4+0+0 | 4 |
--- | 0 | 0 |
三个数字连起来就是"三组" ✓
| 常见值 | 含义 | 用在 |
|---|---|---|
644 ★ | 属主可读写,其他人只读 | 普通文件(配置、网页)✓ |
755 ★ | 属主可读写执行,其他人可读执行 | 目录、可执行程序 ✓ |
600 ★★ | 只有属主可读写 | 含密钥/密码的文件 ✓✓ |
700 | 只有属主可读写执行 | 私有脚本、.ssh |
777 ✗✗ | 所有人可读写执行 | 几乎不该用(见 5.9) |
记忆:
644 = 文件(我能改,别人能看)
755 = 目录/程序(我能改,别人能用)
600 = 秘密(只有我能看能改)★符号表示法(改某一个位时用更方便):
chmod u+x start.sh # 给属主加执行位 ★
chmod g+w file # 给属组加写
chmod o-r file # 去掉其他人的读 ★
chmod a+x file # 所有人加执行(a = all)| 符号 | 谁 |
|---|---|
u | user(属主) |
g | group |
o | other |
a | all(= ugo) |
★ 最常用的一条:chmod +x start.sh(给脚本加执行权限,否则 ./start.sh 会报 Permission denied)✓
chown deploy:deploy /opt/app -R # ★ 递归改属主与属组
chown deploy app.jar # 只改属主
chgrp deploy logs/ # 只改属组-R 递归 ⚠️ ——对整个目录操作时很常用,但也更容易误操作 ✓
典型用法(部署时):
# 用 root 部署后,把应用目录交给 deploy 用户
chown -R deploy:deploy /opt/myapp为什么:应用以 deploy 用户运行,它需要对自己的目录有读写权限(写日志、写临时文件)✓
umask:新建文件的默认权限 实测:
$ umask
0022规则:
文件的"满权限"是 666(rw-rw-rw-)
目录的"满权限"是 777(rwxrwxrwx)
实际权限 = 满权限 - umask所以 umask=0022 时:
| 类型 | 计算 | 实际权限 |
|---|---|---|
| 新建文件 | 666 - 022 | 644(rw-r--r--)✓ |
| 新建目录 | 777 - 022 | 755(rwxr-xr-x)✓ |
这解释了"为什么你 touch 一个新文件,它默认是 644" ✓
常见的 umask:
| umask | 文件 | 目录 | 场景 |
|---|---|---|---|
0022 ★ | 644 | 755 | 默认(其他用户可读)✓ |
0077 | 600 | 700 | 严格(只有自己能访问)✓ |
0002 | 664 | 775 | 组内共享(同组可写)⚠️ |
实践:服务器上处理敏感文件前,可以临时收紧:
umask 0077 # 之后新建的文件都是 600
# ... 操作敏感文件 ...| 位 | 数字 | 作用 |
|---|---|---|
| setuid | 4000 | 执行时以文件属主的身份运行(如 passwd)⚠️ |
| setgid | 2000 | 目录里新建的文件继承目录的属组(团队共享目录有用)✓ |
| sticky | 1000 | 只有文件属主能删自己的文件(/tmp 就是)★ |
sticky 最值得记住:
/tmp 是 1777(drwxrwxrwt)—— 所有人都能写,但**你只能删自己的文件** ✓(末尾的 t 就是 sticky 位)
⚠️ 安全提醒:setuid 的程序要格外小心 ——它会以属主(可能是 root)的权限运行 ✗
sudo useradd -m -s /bin/bash deploy # 建用户(-m 建家目录)★
passwd deploy # 设密码
usermod -aG docker deploy # ★ 加入附加组(-a 是"追加",别漏 ⚠️)
groups deploy # 看属于哪些组
id # 看当前用户(实测:uid=1000(testuser) gid=1000 groups=1000)✓⚠️ usermod -aG 的 -a 不能漏:
usermod -G docker deploy # ✗ 把用户**从其他组移除**了,只剩 docker
usermod -aG docker deploy # ✓ 追加 ✓(这是一条"会把人坑惨"的命令 —— 用户突然失去了原来的组权限 ✗)
sudo 的意义:
平时用普通用户,需要管理员权限时才
sudo✓理由:减少误操作的影响面,且**
sudo会留下日志**(谁在什么时候执行了什么)✓
sudo 的配置(/etc/sudoers,用 visudo 编辑 ⚠️):
deploy ALL=(ALL) NOPASSWD: /bin/systemctl restart myapp # ★ 只允许这一条★ 精细化授权:只给"需要的那一条命令",而不是 ALL=(ALL) ALL ✓
这是本节的"思想" ✓
| 做法 | 说明 |
|---|---|
| 应用用专用用户跑 ★★ | 不要用 root ✗ |
| 应用目录属主是该用户 | chown -R deploy:deploy ✓ |
| 配置文件只给属主读 ★ | 含密码的文件 600 ✓ |
| 只开放需要的端口 | 防火墙(《Linux 服务部署与运维》)✓ |
sudo 精细化 | 只给必要命令 ✓ |
"用 root 跑应用"为什么危险 ★★:
应用有漏洞(如任意文件读取、命令注入)
→ 攻击者获得的权限 = 应用的权限
→ 如果是 root → 整台机器沦陷 ✗✗✗
→ 如果是 deploy → 至少限于该用户的权限 ✓这就是"纵深防御"中的一层:即使应用被攻破,损失也被限制在最小范围 ✓
对照 《Filter、Listener 与会话管理》 的鉴权:两者都是"让每个主体只拥有必需的权限" ✓
chmod 777 危险 这是本节最该记住的一条 ★★★
chmod 777 file # ✗✗ 所有人可读、可写、可执行三个问题:
| 问题 | 说明 |
|---|---|
| ① 任何用户都能改 ✗ | 一个被入侵的低权限账号也能篡改你的应用/配置 |
| ② 任何用户都能执行 ⚠️ | 如果是脚本,等于"任何人都能以你的身份运行它" |
| ③ 掩盖真实需求 ✗ | "777 能跑通"说明你没搞清楚"谁需要什么权限" |
第 ③ 条是关键:
"用 777 解决权限问题"就像"用
@SuppressWarnings("all")解决警告" ——问题还在,只是你看不见了 ✗这与 《代码规范与自动校验》 讲的"滥用抑制注解"是同一类坏习惯 ✓
正确的做法:
① 想清楚:谁(哪个用户)需要访问这个文件?
② 用"属主 + 属组"表达它
③ 给最小够用的权限(644 / 600 / 755)举例:应用要读一个含密码的配置:
chown deploy:deploy app.yml
chmod 600 app.yml # ★ 只有 deploy 能读 ✓(而不是 777)
chmod +x start.sh
./start.sh# 用 root 上传后
chown -R deploy:deploy /opt/myapp
chmod 755 /opt/myapp
chmod 600 /opt/myapp/config/application-prod.yml # ★ 含密码
chmod +x /opt/myapp/bin/start.shchmod -R 777 /opt/myapp chmod -R 777 /opt/myapp # ✗✗后果:
| 后果 | 说明 |
|---|---|
| 任何本地用户都能改代码 | 一个低权限账号就能植入恶意代码 ✗ |
| 配置文件(含密码)所有人可读 | 直接泄漏 ✗✗ |
| 排除了"权限"这一层防护 | 防御深度被削弱 ⚠️ |
而且:-R 让它影响整个目录树 ✗
⚠️ 关于本节的环境(很重要):
本机是 Windows(NTFS),演示环境是 Git Bash(MinGW)。 NTFS 不支持 Unix 权限位 —— MinGW 只是"模拟"显示。
实测结果:
text--- 默认权限 --- -rw-r--r-- 1 testuser 1000 0 Sep 21 16:38 demo.txt --- chmod 600 后 --- -rw-r--r-- 1 testuser 1000 0 Sep 21 16:38 demo.txt ← 没变 ✗ --- chmod 755 后 --- -rw-r--r-- 1 testuser 1000 0 Sep 21 16:38 demo.txt ← 没变 ✗1
2
3
4
5
6所以本节的
chmod效果需要在真实 Linux(或 WSL)上验证 ✓ 能在本机实测的是:ls -l的格式、id、umask(见下)。
可在本机实测的部分:
ls -l README.md labs/pom.xml # 权限位的显示格式
id # 当前用户与组
umask # 默认权限掩码实测输出:
-rw-r--r-- 1 testuser 1000 6494 Sep 21 16:26 README.md
-rw-r--r-- 1 testuser 1000 2555 Sep 21 15:32 labs/pom.xml
uid=1000(testuser) gid=1000 groups=1000
0022三处可以得到什么:
| 输出 | 说明 |
|---|---|
-rw-r--r-- | 属主可读写(6)、属组只读(4)、其他只读(4) = 644 ✓ |
uid=... gid=... groups=... | 当前用户的身份 ✓ |
umask=0022 | 新建文件是 644、目录是 755 ✓ |
还能验证什么(在真实 Linux 上):
| 命令 | 预期 |
|---|---|
chmod 600 f; ls -l f | -rw------- ✓ |
chmod 755 f; ls -l f | -rwxr-xr-x ✓ |
mkdir d; chmod 600 d; cd d | Permission denied(目录缺 x)★ |
umask 0077; touch f; ls -l f | -rw------- ✓ |
touch f; chmod 000 f; cat f —— 观察 Permission denied ✓;mkdir d; echo hi > d/a; chmod 600 d; ls d; cat d/a —— 观察"能列出但读不了" ★;umask 0077; touch f2; ls -l f2 —— 观察 600 ✓;ls -ld <目录> ★:看目录本身的权限(而不是目录里的文件)——排查"进不去"问题时用这个 ✓;namei -l /opt/app/logs/app.log(Linux):把路径上每一级的权限都列出来 ★★ ——"进不去"往往是某一级目录没权限 ✓。chmod 777 解决一切 见 5.9 节。这是本节最该避免的错误 ✗✗
./start.sh # ✗ Permission denied修:chmod +x start.sh ✓
⚠️ 一个延伸:从 Windows 复制脚本到 Linux 后,除了权限,还可能因为 CRLF 换行符导致 /bin/bash^M: bad interpreter ✗ —— 用 dos2unix 或 sed -i 's/\r$//' ✓
usermod -G(漏了 -a) 见 5.7 节。会把用户从其他组移除 ✗
见 5.8 节。
-rw-r--r-- application-prod.yml # ⚠️ 所有用户都能读(里面有数据库密码)修:chmod 600 + chown deploy ✓
这也呼应 《Spring Boot 配置管理与多环境》 的"敏感配置":配置本身要外置,文件的权限也要收紧 ✓
chown -R deploy:deploy /opt/ # ✗ 把 /opt 下**所有**东西都改了修:先 ls 确认路径,再执行 ✓(与 rm -rf 同样的谨慎)
目标:把权限的"读、算、改"练熟(在真实 Linux / WSL 上做效果最好)。
步骤:
ls -l 看几个文件的权限,把权限位翻译成数字(如 rw-r--r-- → 644)✓;touch f; chmod 600 f; ls -l f —— 确认变成 -rw------- ✓;mkdir d; echo hi > d/a.txt; chmod 600 d; ls d; cat d/a.txt —— 观察"能列出但读不了" ★;umask 0077; touch f2; ls -l f2 —— 观察 600 ✓(之后记得改回 0022);chmod +x:写一个一行脚本 echo hello,不加执行位时 ./x.sh 会失败,加了就成功 ✓;ls -ld /opt /var/log —— 理解 -d 的用途 ✓。验收方式:能说出第 3 步"为什么能列出却读不了"。
扩展任务:为一个"部署场景"设计权限方案:
/opt/myapp,以 deploy 用户运行;logs/)、读配置(config/,含密码)、执行启动脚本;chown / chmod 命令;logs/ 与 config/ 的权限应该不同?基础题
r 权限意味着可以 cd 进去。(对 / 错)rwxr-xr-x、rw-------、rwxrwxrwt(提示:最后一组有 sticky)。chmod 777 让程序跑起来"是一个坏做法?代码阅读题
drwxr-x--- 2 deploy deploy 4096 Sep 21 10:00 /opt/myapp/config
-rw------- 1 deploy deploy 512 Sep 21 10:00 /opt/myapp/config/application-prod.yml
drwxrwxrwx 2 deploy deploy 4096 Sep 21 10:00 /opt/myapp/logs
-rwxr-xr-x 1 deploy deploy 120 Sep 21 10:00 /opt/myapp/bin/start.sh编程题
600、目录应为 755、脚本应可执行;stat -c '%a' <file> 取权限的数字表示(这是脚本里取权限的标准做法)★;综合任务
777;提示 1(方向):第 1 题的方向是"x 才是进入"。
提示 2(关键点):第 5 题——logs 目录是 777,想想谁都能往里写会怎样。
提示 3(接近答案):第 7 题的"先做一件事"——考虑"哪件事能同时削弱多条攻击路径"(提示:别用 root 跑)。
x(执行)才是"能否进入" ★r → 可以 ls(列出名字)
x → 可以 cd(进入)+ 访问里面的文件内容 ★
w → 可以在里面增删文件这个区别是本题的全部 ✓ ——也是 5.2 节强调的重点 ✓
一个帮助记忆的比喻:
目录像"一栋楼的走廊":
r= 你能看到走廊上有哪些门(文件名)x= 你能走进走廊并打开门(访问文件内容)只有
r没有x= 你站在外面看门牌,但进不去 ✓
| 权限位 | 分组 | 数字 |
|---|---|---|
rwxr-xr-x | rwx=7, r-x=5, r-x=5 | 755 ✓ |
rw------- | rw-=6, ---=0, ---=0 | 600 ✓ |
rwxrwxrwt | rwx=7, rwx=7, rwt= rwx(7) + sticky(1000) | 1777 ★ |
第三条的 t:t 表示 sticky 位(其他人的执行位 x 被替换成 t)✓
rwxrwxrwx = 777rwxrwxrwt = 1777 ★(/tmp 就是这个)特殊位的数字:
| 位 | 加多少 |
|---|---|
| setuid | +4000 |
| setgid | +2000 |
| sticky | +1000 ✓ |
(所以 chmod 1777 /tmp ✓)
| 理由 | 说明 |
|---|---|
| ① 安全 ✗ | 任何用户都能改 → 一个低权限账号就能篡改 ✗ |
| ② 掩盖问题 ★ | "777 能跑通"说明你没搞清楚"谁需要什么权限" |
| ③ 防御深度被削弱 ⚠️ | 排除了一层防护 |
第二条最值得记住:
777 是"症状缓解",不是"解决问题" ✗
就像"把异常 catch 掉程序就不崩了" ——问题还在,只是你看不到 ✓
正确做法:花 2 分钟想清楚"谁需要访问",然后给最小权限 ✓
一个真实的后续:777 设上去之后,几乎没人会再去改回来 ——它会一直留在生产环境里 ✗✗
所以"临时用一下"这个理由不成立 ✓ ——因为它不会是临时的 ✓
第 4 题:逐行说明
| 路径 | 权限 | 含义 |
|---|---|---|
config/ | drwxr-x---(750) | 属主 deploy 可读写进入;属组 deploy 可读、可进入(不能写);其他人无任何权限 ✓ |
application-prod.yml | -rw-------(600) | 只有 deploy 能读写 ✓(含密码,合适 ✓) |
logs/ | drwxrwxrwx(777) | 所有人都可读、可写、可进入 ✗ 不合适 |
bin/start.sh | -rwxr-xr-x(755) | 属主可读写执行,其他人可读可执行 ✓(合适) |
第 5 题:logs/ 的 777 不合适 ✗
问题:
| 问题 | 说明 |
|---|---|
| 任何用户都能往日志目录写文件 ✗ | 可以塞入任意文件(脚本、木马) |
| 任何用户都能删日志 ✗✗ | 攻击者可以销毁痕迹 ——这在安全事件里是最糟的 |
| 如果日志里有敏感信息 | 所有用户都能读 ⚠️ |
"能删日志"这一条尤其严重:
日志是事后追溯的唯一依据 ✓ ——如果攻击者能删日志,你就永远不知道发生了什么 ✗✗
改成什么:
chmod 750 /opt/myapp/logs # ★ 属主读写进入,属组可读可进入
# 或者(如果只有 deploy 需要):
chmod 700 /opt/myapp/logs为什么 750 而不是 755:
750 = 属主 rwx、属组 r-x、**其他人无权限** ✓
755 = 其他人也能 r-x(能读日志)⚠️日志目录通常不需要"其他人"访问 ——需要看日志的人应该被加进 deploy 组,而不是开放给所有人 ✓
这正是 5.8 的"最小权限":
"谁能看日志"这个问题,答案应该是"deploy 组",而不是"所有人" ✓
想给谁看 → 把他加进组(usermod -aG) ✓ ——而不是放宽权限 ✓
另一个相关建议:日志应该考虑"只追加"(append-only):
chattr +a /opt/myapp/logs/app.log # Linux:只能追加,不能删改(需 root 权限设置)(这能防止攻击者篡改已有日志 ✓,但需要权衡"日志轮转"的需求 ⚠️)
#!/usr/bin/env bash
# check-perms.sh —— 部署后的权限检查
set -uo pipefail
APP_DIR="${1:-/opt/myapp}"
problems=0
# 期望值:路径 -> 期望的八进制权限
# 格式:"路径:期望权限"
EXPECTATIONS=(
"$APP_DIR:755"
"$APP_DIR/config:750"
"$APP_DIR/config/application-prod.yml:600"
"$APP_DIR/logs:750"
"$APP_DIR/bin/start.sh:755"
)
echo "===== 权限检查 ====="
for entry in "${EXPECTATIONS[@]}"; do
path="${entry%:*}"
want="${entry##*:}"
if [ ! -e "$path" ]; then
echo " [缺失] $path"
problems=$((problems + 1))
continue
fi
# ★ stat -c '%a' 取权限的数字表示(脚本里取权限的标准做法)
actual=$(stat -c '%a' "$path" 2>/dev/null)
if [ "$actual" = "$want" ]; then
echo " [OK] $path = $actual"
else
echo " [问题] $path 期望 $want,实际 $actual"
problems=$((problems + 1))
fi
done
# 额外检查:配置文件不能被"其他人"读(这是最容易出问题的一条)
for conf in "$APP_DIR"/config/*.yml; do
[ -e "$conf" ] || continue
perm=$(stat -c '%a' "$conf")
others=$(( 0${perm: -1} )) # 取最后一位(other 的权限)
if [ $(( others & 4 )) -ne 0 ]; then
echo " [严重] $conf 对其他用户可读(权限 $perm),可能泄漏密钥"
problems=$((problems + 1))
fi
done
echo ""
if [ "$problems" -eq 0 ]; then
echo "全部通过 ✓"
exit 0
fi
echo "发现 $problems 个权限问题 ✗"
exit 1关键点:
| # | 做法 | 说明 |
|---|---|---|
| ① | stat -c '%a' ★ | 脚本里取权限的标准方式(不要用 ls -l 去解析文本)✓ |
| ② | "期望值 vs 实际值" 都要打印 | 只说"不对"没用,要说"应该是什么、现在是什么" ✓ |
| ③ | others & 4 ★ | 位运算判断"其他人是否可读"(4 = r)✓ ——比"必须等于 600"更灵活 |
| ④ | 退出码 1 ★ | 接进 CI 的关键(《代码规范与自动校验》)✓ |
| ⑤ | "缺失"与"权限不对"分开报 | 两类问题,修法不同 ✓ |
第 ③ 条值得展开:
与其要求"必须 600",不如检查"其他人不能有 r/w" ✓
因为
640(属组可读)也可能是合理的 ——只要"其他人"没有权限就行 ✓这就是"检查本质而非检查形式":安全要求是"不该被无关的人读到",而不是"必须恰好是 600" ✓
为什么"部署后自动检查权限"值得做
| 理由 | 说明 |
|---|---|
| 权限问题很隐蔽 ⚠️ | 应用能正常跑,只是"太开放" ——功能测试发现不了 ✗ |
| 手工操作容易漏 | 部署步骤多,chmod 是最容易被忘的一步 ✗ |
| 会随时间退化 ★ | 有人"临时"改了权限 → 忘了改回来 → 一直留在生产 ✗✗ |
| 可审计 | 每次部署都有记录,能发现"什么时候变松的" ✓ |
| 成本极低 | 一个几十行的脚本 ✓ |
第三条最关键:
权限问题不是"一次性"的 ——它会因为"临时处理"而随时间变松 ✓
定期检查能把这个"熵增"逆转回来 ✓
这与 《代码规范与自动校验》 的"规范检查接进 CI"、T1-018 的"覆盖率门禁"是同一种思路:用自动检查对抗"随时间退化" ✓
入侵路径分析(两条)
路径一:通过"文件上传"功能 ★★(最可能)
① 应用有"上传文件"功能,**没限制文件类型**
② 攻击者上传一个脚本(如 .jsp / .sh,或绕过限制的文件)
③ 应用目录是 777 → **任何用户都能写** → 上传成功
④ 应用以 root 运行 → **上传的脚本以 root 权限执行** ✗✗
⑤ 挖矿程序被下载并运行 ✓这条路径里,每一个"缺陷"都是必需的:
| 缺陷 | 作用 |
|---|---|
| 上传没限制类型 | 让攻击者能把文件放进来 ✗ |
| 目录 777 | 让"写入"不需要任何权限 ✗ |
| 以 root 运行 | 让执行的脚本拥有最高权限 ✗✗ |
★ 这就是"纵深防御"的反面教材:三层防线全部失效 ——任何一层有效,攻击都不会成功 ✓
路径二:通过共享 SSH 账号
① 部署用的 SSH 账号是共享的(多人知道密码)
② 密码可能泄露(聊天记录、离职员工、暴力破解)
③ 该账号能部署 → 能往应用目录写文件
④ 目录 777 → 写文件无障碍
⑤ 应用以 root 运行 → 拿到 root ✗这条路径的关键:共享账号无法追责(不知道是谁),且密码更容易扩散 ✗
加固措施(对应每一条)
| # | 问题 | 加固 |
|---|---|---|
| 1 | 上传没限制类型 | 白名单(只允许图片/PDF 等)+ 校验文件内容(不只信扩展名)+ 上传目录不可执行 ★ + 重命名存储(不保留原名)+ 大小限制 ✓ |
| 2 | 目录 777 | chown -R deploy:deploy + chmod 750(或按需 755)✓ |
| 3 | 以 root 运行 ★★ | 建 deploy 用户,应用以它运行(《Linux 服务部署与运维》 的 systemd User=deploy)✓✓ |
| 4 | 共享 SSH 账号 | 每人一个账号 + SSH 密钥登录(禁密码)+ sudo 精细化 ✓ |
| 5 | 无法发现 | 文件完整性监控(如 AIDE)+ 日志集中收集(攻击者删本地日志也没用)★ |
第 5 条特别重要:
日志要"实时送到别的地方"(日志服务 / 对象存储)✓ ——这样攻击者删了本机日志也抹不掉痕迹 ✓
这与 《日志框架与日志规范》 讲的"日志是黑匣子"呼应:黑匣子必须放在不会一起坠毁的地方 ✓
纵深防御的层次
| 层 | 措施 | 缺失时 |
|---|---|---|
| ① 应用层 | 上传白名单、参数校验 | 攻击者能放进任意文件 ✗ |
| ② 进程层 ★ | 非 root 运行 | 放进来就能做一切 ✗✗ |
| ③ 文件系统层 | 权限 750/600 | 放进来能写 ✗ |
| ④ 账号层 | 独立账号 + 密钥 + sudo | 能直接登录 ✗ |
| ⑤ 网络层 | 防火墙只开必要端口 | 能直接访问 ✗ |
| ⑥ 监控层 | 日志外送 + 完整性监控 | 发生了也不知道 ✗✗ |
本案例中:①②③④ 全失效,所以攻击畅通无阻 ✓
纵深防御的含义:每一层都"可能"被突破,但攻击者需要连续突破所有层 ✓
所以"修一层"就有价值 ——但修得越多越安全 ✓
只做一件事,先做哪件
答:让应用不以 root 运行(建 deploy 用户)✓
理由:
| 理由 | 说明 |
|---|---|
| 削弱面最广 ★★ | 它同时削弱了路径一与路径二 ——两条路径的最后一步都依赖 root ✓✓ |
| 成本低 | 建个用户 + 改一下 service 配置 ✓ |
| 不改变功能 | 只要权限配好,应用行为不变 ✓ |
| 是"根因级"的修复 ★ | 其他措施(如上传白名单)只挡一条路径;这个挡的是"后果的严重程度" ✓ |
为什么"削弱面最广"最重要:
修"上传白名单" → 挡住路径一,但**挡不住路径二**(SSH 泄露)
修"非 root 运行" → 两条路径都还在发生,**但攻击者拿到的权限从 root 降级为 deploy** ✓
→ 无法装系统级挖矿、无法改系统配置、破坏被限制在应用目录 ✓✓这就是"降低影响面"与"阻断路径"的区别:
阻断路径(上传白名单):挡住已知的这一条,但未知的入口还在 ✗
降低影响面(非 root):不管从哪进来的,损失都有限 ✓✓
理想的是两者都做 ——但在只能做一件时,"降低影响面"更稳健 ✓
这与安全领域的"假定失守"(Assume Breach)思路一致:
不假设"我挡得住所有攻击",而是假设"总有一处会被突破" ——然后确保"突破了也不会全盘皆输" ✓
对照 《Git Flow 与团队协作》 与 《代码规范与自动校验》:共同的设计哲学
| 《Git Flow 与团队协作》 分支保护 | 《代码规范与自动校验》 规范检查 | 本题 最小权限 | |
|---|---|---|---|
| 防什么 | 有人绕过 review | 不合规范的代码入库 | 攻击者拿到过大权限 |
| 形式 | 平台规则 | CI 检查 | 进程身份 + 文件权限 |
| 依赖人吗 | 否 ✓ | 否 ✓ | 否 ✓ |
| 默认 | 拒绝 | 失败即阻断 | 最小 |
共同原则(本知识库反复出现):
① 把约定变成机制 ——"请大家不要…"不可靠,"系统不允许"才可靠 ✓
② 默认拒绝,显式放行 ——权限默认最小、分支默认保护、规范默认检查 ✓
③ 纵深防御 ——不依赖单点(《Git Flow 与团队协作》 的三层:编辑器/本地/CI;本题的六层)✓
④ 假定失守 ——就算某一层被突破,损失也要可控 ✓
一句话总结:
权限管理、分支保护、规范检查,看起来是三件不同的事,本质上都是同一件事:用可执行的机制,把"我们希望的状态"固定下来,而不是期待每个人每次都做对。 ✓
因为人的注意力是稀缺且不可靠的,而机制不是。 ✓
ls -l 的每一列(尤其权限位与文件类型);rw-r--r-- 等表示 ★★★;chmod(数字与符号两种写法)与 chown;umask 与默认权限的关系(022 → 文件 644 / 目录 755);/tmp 是 1777);chmod 777 危险" ★★★;《Linux 服务部署与运维》:把应用真正"跑起来"并让它开机自启。
暂无