Skip to content

Linux 文件、用户与权限管理 ​

S3-033建议学进阶约 60 分钟JDK 21企业开发基础 · Linux 与 Shell

1. 本节定位 ​

《Linux 常用命令与部署》 用了 ls -l,输出里有这么一串:

text
-rw-r--r-- 1 testuser 1000 6494 Sep 21 16:26 README.md

本节就是把这串"天书"讲清楚 ✓

它为什么重要:

text
"服务起不来,报 Permission denied"
"我明明有文件,为什么读不出来"
"同事能改我的配置文件?"
        ↓
        都是权限问题

2. 学习目标 ​

完成本节后,你应该能够:

  • 读懂 ls -l 的每一列(尤其权限位)★;
  • 说出权限的三组(属主 / 属组 / 其他)与三类(读 / 写 / 执行);
  • 熟练使用数字表示法(644 / 755 / 600)★★★;
  • 说出"目录的执行位"与"文件的执行位"含义不同 ★★;
  • 会用 chmod / chown;
  • 说出 umask 与新建文件默认权限的关系;
  • 理解 sudo 的意义;
  • 能解释"为什么 chmod 777 是危险的" ★★★;
  • 知道部署时最小权限原则该怎么落地 ✓。

3. 前置知识检查 ​

4. 为什么需要这个知识 ​

权限是 Linux 安全的第一道防线 ✓

三个真实场景:

场景权限怎么起作用
部署的应用不该能删系统文件用专用用户(如 deploy)跑,它没权限 ✓
配置文件里有数据库密码文件权限设为 600(只有属主能读)★
多个开发共用一个部署账号用"组"管理,避免互相改坏 ✓

它也是"最小权限原则"在操作系统层的落地:

一个进程只应该拥有"完成工作所必需"的权限 ✓

这与 《Filter、Listener 与会话管理》 的"默认拒绝 + 白名单"、《Git Flow 与团队协作》 的"分支保护"是同一条原则 ✓

5. 核心概念 ​

5.1 ls -l 的每一列 ​

实测输出:

text
-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 / psocket / 管道

5.2 权限位:三组 × 三类 ​

text
-rw-r--r--
│└┬┘└┬┘└┬┘
│ │  │  └── other(其他人)
│ │  └───── group(属组)
│ └──────── user(属主)
└────────── 文件类型

三类权限:

字符含义对文件对目录 ★
r(4)读读内容列出目录内容(ls)
w(2)写改内容在目录里增删文件
x(1)执行当程序运行进入目录(cd)★★

★ 目录的 x 是关键(这一条最容易搞错):

对目录来说,"执行"="能否 cd 进去" ✓

一个目录如果没有 x,即使有 r,你也只能"看到文件名",不能读文件内容、不能进入 ✗

实测体会:

bash
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 ✓

5.3 数字表示法 ​

每个三位的组,用 r=4 / w=2 / x=1 相加 ✓

权限计算数字
rw-4+2+06
r-x4+0+15
rwx4+2+17
r--4+0+04
---00

三个数字连起来就是"三组" ✓

常见值含义用在
644 ★属主可读写,其他人只读普通文件(配置、网页)✓
755 ★属主可读写执行,其他人可读执行目录、可执行程序 ✓
600 ★★只有属主可读写含密钥/密码的文件 ✓✓
700只有属主可读写执行私有脚本、.ssh
777 ✗✗所有人可读写执行几乎不该用(见 5.9)

记忆:

text
644 = 文件(我能改,别人能看)
755 = 目录/程序(我能改,别人能用)
600 = 秘密(只有我能看能改)★

符号表示法(改某一个位时用更方便):

bash
chmod u+x start.sh        # 给属主加执行位 ★
chmod g+w file            # 给属组加写
chmod o-r file            # 去掉其他人的读 ★
chmod a+x file            # 所有人加执行(a = all)
符号谁
uuser(属主)
ggroup
oother
aall(= ugo)

★ 最常用的一条:chmod +x start.sh(给脚本加执行权限,否则 ./start.sh 会报 Permission denied)✓

5.4 修改属主与属组 ​

bash
chown deploy:deploy /opt/app -R       # ★ 递归改属主与属组
chown deploy app.jar                  # 只改属主
chgrp deploy logs/                    # 只改属组

-R 递归 ⚠️ ——对整个目录操作时很常用,但也更容易误操作 ✓

典型用法(部署时):

bash
# 用 root 部署后,把应用目录交给 deploy 用户
chown -R deploy:deploy /opt/myapp

为什么:应用以 deploy 用户运行,它需要对自己的目录有读写权限(写日志、写临时文件)✓

5.5 umask:新建文件的默认权限 ​

实测:

bash
$ umask
0022

规则:

text
文件的"满权限"是 666(rw-rw-rw-)
目录的"满权限"是 777(rwxrwxrwx)

实际权限 = 满权限 - umask

所以 umask=0022 时:

类型计算实际权限
新建文件666 - 022644(rw-r--r--)✓
新建目录777 - 022755(rwxr-xr-x)✓

这解释了"为什么你 touch 一个新文件,它默认是 644" ✓

常见的 umask:

umask文件目录场景
0022 ★644755默认(其他用户可读)✓
0077600700严格(只有自己能访问)✓
0002664775组内共享(同组可写)⚠️

实践:服务器上处理敏感文件前,可以临时收紧:

bash
umask 0077          # 之后新建的文件都是 600
# ... 操作敏感文件 ...

5.6 特殊权限位(了解即可) ​

位数字作用
setuid4000执行时以文件属主的身份运行(如 passwd)⚠️
setgid2000目录里新建的文件继承目录的属组(团队共享目录有用)✓
sticky1000只有文件属主能删自己的文件(/tmp 就是)★

sticky 最值得记住:

text
/tmp 是 1777(drwxrwxrwt)—— 所有人都能写,但**你只能删自己的文件** ✓

(末尾的 t 就是 sticky 位)

⚠️ 安全提醒:setuid 的程序要格外小心 ——它会以属主(可能是 root)的权限运行 ✗

5.7 用户与 sudo ​

bash
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 不能漏:

bash
usermod -G docker deploy     # ✗ 把用户**从其他组移除**了,只剩 docker
usermod -aG docker deploy    # ✓ 追加 ✓

(这是一条"会把人坑惨"的命令 —— 用户突然失去了原来的组权限 ✗)

sudo 的意义:

平时用普通用户,需要管理员权限时才 sudo ✓

理由:减少误操作的影响面,且**sudo 会留下日志**(谁在什么时候执行了什么)✓

sudo 的配置(/etc/sudoers,用 visudo 编辑 ⚠️):

text
deploy ALL=(ALL) NOPASSWD: /bin/systemctl restart myapp      # ★ 只允许这一条

★ 精细化授权:只给"需要的那一条命令",而不是 ALL=(ALL) ALL ✓

5.8 最小权限原则 ​

这是本节的"思想" ✓

做法说明
应用用专用用户跑 ★★不要用 root ✗
应用目录属主是该用户chown -R deploy:deploy ✓
配置文件只给属主读 ★含密码的文件 600 ✓
只开放需要的端口防火墙(《Linux 服务部署与运维》)✓
sudo 精细化只给必要命令 ✓

"用 root 跑应用"为什么危险 ★★:

text
应用有漏洞(如任意文件读取、命令注入)
  → 攻击者获得的权限 = 应用的权限
  → 如果是 root → 整台机器沦陷 ✗✗✗
  → 如果是 deploy → 至少限于该用户的权限 ✓

这就是"纵深防御"中的一层:即使应用被攻破,损失也被限制在最小范围 ✓

对照 《Filter、Listener 与会话管理》 的鉴权:两者都是"让每个主体只拥有必需的权限" ✓

5.9 为什么 chmod 777 危险 ​

这是本节最该记住的一条 ★★★

bash
chmod 777 file        # ✗✗ 所有人可读、可写、可执行

三个问题:

问题说明
① 任何用户都能改 ✗一个被入侵的低权限账号也能篡改你的应用/配置
② 任何用户都能执行 ⚠️如果是脚本,等于"任何人都能以你的身份运行它"
③ 掩盖真实需求 ✗"777 能跑通"说明你没搞清楚"谁需要什么权限"

第 ③ 条是关键:

"用 777 解决权限问题"就像"用 @SuppressWarnings("all") 解决警告" ——问题还在,只是你看不见了 ✗

这与 《代码规范与自动校验》 讲的"滥用抑制注解"是同一类坏习惯 ✓

正确的做法:

text
① 想清楚:谁(哪个用户)需要访问这个文件?
② 用"属主 + 属组"表达它
③ 给最小够用的权限(644 / 600 / 755)

举例:应用要读一个含密码的配置:

bash
chown deploy:deploy app.yml
chmod 600 app.yml        # ★ 只有 deploy 能读 ✓

(而不是 777)

6. 递进示例 ​

6.1 最小示例:让脚本可执行 ​

bash
chmod +x start.sh
./start.sh

6.2 业务示例:部署时的权限设置 ​

bash
# 用 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.sh

6.3 反例:chmod -R 777 /opt/myapp ​

bash
chmod -R 777 /opt/myapp        # ✗✗

后果:

后果说明
任何本地用户都能改代码一个低权限账号就能植入恶意代码 ✗
配置文件(含密码)所有人可读直接泄漏 ✗✗
排除了"权限"这一层防护防御深度被削弱 ⚠️

而且:-R 让它影响整个目录树 ✗

7. 实测与说明 ​

⚠️ 关于本节的环境(很重要):

本机是 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      ← 没变 ✗

所以本节的 chmod 效果需要在真实 Linux(或 WSL)上验证 ✓ 能在本机实测的是:ls -l 的格式、id、umask(见下)。

可在本机实测的部分:

bash
ls -l README.md labs/pom.xml       # 权限位的显示格式
id                                  # 当前用户与组
umask                               # 默认权限掩码

实测输出:

text
-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 dPermission denied(目录缺 x)★
umask 0077; touch f; ls -l f-rw------- ✓

8. Debug 观察点 ​

  1. 在真实 Linux 上:touch f; chmod 000 f; cat f —— 观察 Permission denied ✓;
  2. 验证"目录的 x":mkdir d; echo hi > d/a; chmod 600 d; ls d; cat d/a —— 观察"能列出但读不了" ★;
  3. 验证 umask:umask 0077; touch f2; ls -l f2 —— 观察 600 ✓;
  4. ls -ld <目录> ★:看目录本身的权限(而不是目录里的文件)——排查"进不去"问题时用这个 ✓;
  5. namei -l /opt/app/logs/app.log(Linux):把路径上每一级的权限都列出来 ★★ ——"进不去"往往是某一级目录没权限 ✓。

9. 常见错误 ​

错误 1:chmod 777 解决一切 ​

见 5.9 节。这是本节最该避免的错误 ✗✗

错误 2:忘了给脚本加执行位 ​

bash
./start.sh        # ✗ Permission denied

修:chmod +x start.sh ✓

⚠️ 一个延伸:从 Windows 复制脚本到 Linux 后,除了权限,还可能因为 CRLF 换行符导致 /bin/bash^M: bad interpreter ✗ —— 用 dos2unix 或 sed -i 's/\r$//' ✓

错误 3:usermod -G(漏了 -a) ​

见 5.7 节。会把用户从其他组移除 ✗

错误 4:用 root 跑应用 ​

见 5.8 节。

错误 5:配置文件权限太松 ​

bash
-rw-r--r-- application-prod.yml        # ⚠️ 所有用户都能读(里面有数据库密码)

修:chmod 600 + chown deploy ✓

这也呼应 《Spring Boot 配置管理与多环境》 的"敏感配置":配置本身要外置,文件的权限也要收紧 ✓

错误 6:递归操作前不确认 ​

bash
chown -R deploy:deploy /opt/        # ✗ 把 /opt 下**所有**东西都改了

修:先 ls 确认路径,再执行 ✓(与 rm -rf 同样的谨慎)

10. 动手实验 ​

目标:把权限的"读、算、改"练熟(在真实 Linux / WSL 上做效果最好)。

步骤:

  1. ls -l 看几个文件的权限,把权限位翻译成数字(如 rw-r--r-- → 644)✓;
  2. 在真实 Linux 上:touch f; chmod 600 f; ls -l f —— 确认变成 -rw------- ✓;
  3. 验证目录的 x:mkdir d; echo hi > d/a.txt; chmod 600 d; ls d; cat d/a.txt —— 观察"能列出但读不了" ★;
  4. 验证 umask:umask 0077; touch f2; ls -l f2 —— 观察 600 ✓(之后记得改回 0022);
  5. 练习 chmod +x:写一个一行脚本 echo hello,不加执行位时 ./x.sh 会失败,加了就成功 ✓;
  6. 看目录本身的权限:ls -ld /opt /var/log —— 理解 -d 的用途 ✓。

验收方式:能说出第 3 步"为什么能列出却读不了"。

扩展任务:为一个"部署场景"设计权限方案:

  • 应用装在 /opt/myapp,以 deploy 用户运行;
  • 需要:写日志(logs/)、读配置(config/,含密码)、执行启动脚本;
  • 要求:写出完整的 chown / chmod 命令;
  • 说明:为什么 logs/ 与 config/ 的权限应该不同?

11. 练习题 ​

基础题

  1. 判断:对目录来说,r 权限意味着可以 cd 进去。(对 / 错)
  2. 把下列权限翻译成数字:rwxr-xr-x、rw-------、rwxrwxrwt(提示:最后一组有 sticky)。
  3. 简答:为什么"用 chmod 777 让程序跑起来"是一个坏做法?

代码阅读题

bash
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
  1. 逐行说明这些权限的含义(谁可以做什么);
  2. 哪一项的权限设置不合适?应该怎么改?

编程题

  1. 写一个"权限检查脚本":
    • 需求:部署后检查关键路径的权限是否符合预期;
    • 要求:
      • 检查列表:配置文件应为 600、目录应为 755、脚本应可执行;
      • 不符合就报错并给出"期望值 vs 实际值";
      • 退出码:有问题返回 1(这样能接进 CI,见 《代码规范与自动校验》)✓;
      • 用 stat -c '%a' <file> 取权限的数字表示(这是脚本里取权限的标准做法)★;
    • 回答:为什么"部署后自动检查权限"值得做?

综合任务

  1. 为一次"服务器被入侵"做复盘,并给出加固方案:
    • 背景:一台服务器上跑着 Java 应用,某天被发现有人在应用目录里放了挖矿程序;
    • 调查发现:
      • 应用以 root 运行;
      • 应用目录是 777;
      • 部署用的 SSH 账号是共享的(多人知道密码);
      • 应用有一个"上传文件"功能,且没限制文件类型;
    • 要求:
      • 分析入侵路径( attackers 是怎么进来的?至少给出两条可能的路径);
      • 针对每一条给出加固措施;
      • 说明"纵深防御"在这个案例里应该是哪几层;
      • 说明"如果只做一件事,先做哪件"并说明理由;
    • 额外要求:把这次事故对照 《Git Flow 与团队协作》 的"分支保护"与 《代码规范与自动校验》 的"规范检查",说明它们共同的设计哲学。
分级提示

提示 1(方向):第 1 题的方向是"x 才是进入"。

提示 2(关键点):第 5 题——logs 目录是 777,想想谁都能往里写会怎样。

提示 3(接近答案):第 7 题的"先做一件事"——考虑"哪件事能同时削弱多条攻击路径"(提示:别用 root 跑)。

12. 参考答案 ​

基础题
  1. 错。对目录来说,x(执行)才是"能否进入" ★
text
r  → 可以 ls(列出名字)
x  → 可以 cd(进入)+ 访问里面的文件内容 ★
w  → 可以在里面增删文件

这个区别是本题的全部 ✓ ——也是 5.2 节强调的重点 ✓

一个帮助记忆的比喻:

目录像"一栋楼的走廊":

  • r = 你能看到走廊上有哪些门(文件名)
  • x = 你能走进走廊并打开门(访问文件内容)

只有 r 没有 x = 你站在外面看门牌,但进不去 ✓

  1. 翻译:
权限位分组数字
rwxr-xr-xrwx=7, r-x=5, r-x=5755 ✓
rw-------rw-=6, ---=0, ---=0600 ✓
rwxrwxrwtrwx=7, rwx=7, rwt= rwx(7) + sticky(1000)1777 ★

第三条的 t:t 表示 sticky 位(其他人的执行位 x 被替换成 t)✓

  • rwxrwxrwx = 777
  • rwxrwxrwt = 1777 ★(/tmp 就是这个)

特殊位的数字:

位加多少
setuid+4000
setgid+2000
sticky+1000 ✓

(所以 chmod 1777 /tmp ✓)

  1. 三个理由(5.9):
理由说明
① 安全 ✗任何用户都能改 → 一个低权限账号就能篡改 ✗
② 掩盖问题 ★"777 能跑通"说明你没搞清楚"谁需要什么权限"
③ 防御深度被削弱 ⚠️排除了一层防护

第二条最值得记住:

777 是"症状缓解",不是"解决问题" ✗

就像"把异常 catch 掉程序就不崩了" ——问题还在,只是你看不到 ✓

正确做法:花 2 分钟想清楚"谁需要访问",然后给最小权限 ✓

一个真实的后续:777 设上去之后,几乎没人会再去改回来 ——它会一直留在生产环境里 ✗✗

所以"临时用一下"这个理由不成立 ✓ ——因为它不会是临时的 ✓

代码阅读题(第 4、5 题)

第 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 不合适 ✗

问题:

问题说明
任何用户都能往日志目录写文件 ✗可以塞入任意文件(脚本、木马)
任何用户都能删日志 ✗✗攻击者可以销毁痕迹 ——这在安全事件里是最糟的
如果日志里有敏感信息所有用户都能读 ⚠️

"能删日志"这一条尤其严重:

日志是事后追溯的唯一依据 ✓ ——如果攻击者能删日志,你就永远不知道发生了什么 ✗✗

改成什么:

bash
chmod 750 /opt/myapp/logs          # ★ 属主读写进入,属组可读可进入
# 或者(如果只有 deploy 需要):
chmod 700 /opt/myapp/logs

为什么 750 而不是 755:

text
750 = 属主 rwx、属组 r-x、**其他人无权限** ✓
755 = 其他人也能 r-x(能读日志)⚠️

日志目录通常不需要"其他人"访问 ——需要看日志的人应该被加进 deploy 组,而不是开放给所有人 ✓

这正是 5.8 的"最小权限":

"谁能看日志"这个问题,答案应该是"deploy 组",而不是"所有人" ✓

想给谁看 → 把他加进组(usermod -aG) ✓ ——而不是放宽权限 ✓

另一个相关建议:日志应该考虑"只追加"(append-only):

bash
chattr +a /opt/myapp/logs/app.log      # Linux:只能追加,不能删改(需 root 权限设置)

(这能防止攻击者篡改已有日志 ✓,但需要权衡"日志轮转"的需求 ⚠️)

编程题(第 6 题)
bash
#!/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 的"覆盖率门禁"是同一种思路:用自动检查对抗"随时间退化" ✓

综合任务(第 7 题)

入侵路径分析(两条)

路径一:通过"文件上传"功能 ★★(最可能)

text
① 应用有"上传文件"功能,**没限制文件类型**
② 攻击者上传一个脚本(如 .jsp / .sh,或绕过限制的文件)
③ 应用目录是 777 → **任何用户都能写** → 上传成功
④ 应用以 root 运行 → **上传的脚本以 root 权限执行** ✗✗
⑤ 挖矿程序被下载并运行 ✓

这条路径里,每一个"缺陷"都是必需的:

缺陷作用
上传没限制类型让攻击者能把文件放进来 ✗
目录 777让"写入"不需要任何权限 ✗
以 root 运行让执行的脚本拥有最高权限 ✗✗

★ 这就是"纵深防御"的反面教材:三层防线全部失效 ——任何一层有效,攻击都不会成功 ✓

路径二:通过共享 SSH 账号

text
① 部署用的 SSH 账号是共享的(多人知道密码)
② 密码可能泄露(聊天记录、离职员工、暴力破解)
③ 该账号能部署 → 能往应用目录写文件
④ 目录 777 → 写文件无障碍
⑤ 应用以 root 运行 → 拿到 root ✗

这条路径的关键:共享账号无法追责(不知道是谁),且密码更容易扩散 ✗

加固措施(对应每一条)

#问题加固
1上传没限制类型白名单(只允许图片/PDF 等)+ 校验文件内容(不只信扩展名)+ 上传目录不可执行 ★ + 重命名存储(不保留原名)+ 大小限制 ✓
2目录 777chown -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 配置 ✓
不改变功能只要权限配好,应用行为不变 ✓
是"根因级"的修复 ★其他措施(如上传白名单)只挡一条路径;这个挡的是"后果的严重程度" ✓

为什么"削弱面最广"最重要:

text
修"上传白名单"    → 挡住路径一,但**挡不住路径二**(SSH 泄露)
修"非 root 运行"  → 两条路径都还在发生,**但攻击者拿到的权限从 root 降级为 deploy** ✓
                    → 无法装系统级挖矿、无法改系统配置、破坏被限制在应用目录 ✓✓

这就是"降低影响面"与"阻断路径"的区别:

阻断路径(上传白名单):挡住已知的这一条,但未知的入口还在 ✗

降低影响面(非 root):不管从哪进来的,损失都有限 ✓✓

理想的是两者都做 ——但在只能做一件时,"降低影响面"更稳健 ✓

这与安全领域的"假定失守"(Assume Breach)思路一致:

不假设"我挡得住所有攻击",而是假设"总有一处会被突破" ——然后确保"突破了也不会全盘皆输" ✓

对照 《Git Flow 与团队协作》 与 《代码规范与自动校验》:共同的设计哲学

《Git Flow 与团队协作》 分支保护《代码规范与自动校验》 规范检查本题 最小权限
防什么有人绕过 review不合规范的代码入库攻击者拿到过大权限
形式平台规则CI 检查进程身份 + 文件权限
依赖人吗否 ✓否 ✓否 ✓
默认拒绝失败即阻断最小

共同原则(本知识库反复出现):

① 把约定变成机制 ——"请大家不要…"不可靠,"系统不允许"才可靠 ✓

② 默认拒绝,显式放行 ——权限默认最小、分支默认保护、规范默认检查 ✓

③ 纵深防御 ——不依赖单点(《Git Flow 与团队协作》 的三层:编辑器/本地/CI;本题的六层)✓

④ 假定失守 ——就算某一层被突破,损失也要可控 ✓

一句话总结:

权限管理、分支保护、规范检查,看起来是三件不同的事,本质上都是同一件事:用可执行的机制,把"我们希望的状态"固定下来,而不是期待每个人每次都做对。 ✓

因为人的注意力是稀缺且不可靠的,而机制不是。 ✓

13. 掌握标准 ​

  • [ ] 能读懂 ls -l 的每一列(尤其权限位与文件类型);
  • [ ] 能说出"目录的 x"是"能否进入" ★;
  • [ ] 能熟练换算 644 / 755 / 600 与 rw-r--r-- 等表示 ★★★;
  • [ ] 会用 chmod(数字与符号两种写法)与 chown;
  • [ ] 知道 umask 与默认权限的关系(022 → 文件 644 / 目录 755);
  • [ ] 知道 sticky 位的作用(/tmp 是 1777);
  • [ ] 能解释"为什么 chmod 777 危险" ★★★;
  • [ ] 知道部署时"应用不该以 root 运行" ★★;
  • [ ] 理解最小权限原则,并能落地到具体命令。

14. 扩展资源 ​

15. 下一步学习 ​

《Linux 服务部署与运维》:把应用真正"跑起来"并让它开机自启。

后续知识

暂无

进度只保存在本机浏览器,可随时清除

个人学习项目:AI 生成内容均经人工复核,第三方资源仅作索引