
前段时间帮同事排查一个生产环境的问题他折腾了大半天最后发现就是权限没配对。这个场景我见过太多次了不管是刚接触 Linux 的新手还是写了好几年代码的老手跟权限打交道时多少都栽过跟头。Linux 权限这个事说大不大说小不小但它就是那种平时用不到、一用到就卡壳的知识点。所以这期就把权限这个东西整个拆开揉碎了讲一遍从底层原理到高频命令再到实际排错思路争取一篇文章帮你把这块地基打牢。Linux 不是一个像 Windows 那样习惯用可视化界面管理的操作系统绝大部分操作都靠命令行完成。而权限就是你在这套系统里所有操作能不能顺利执行的根本。简单说权限决定了谁能读文件、谁能写文件、谁能执行程序谁能进某个目录。今天这篇主要面向 Linux 初学者、运维新手以及那些一直用复制粘贴命令但不知道原理的朋友。我会用最贴近实际操作的讲法把 Linux 权限相关的知识点讲明白。1. 权限体系设计思路拆解1.1 为什么 Linux 要把权限设计得这么较真很多人第一次接触 Linux最不习惯的就是动不动Permission denied。你可能会想我就改个文件怎么这么多事但正是这种较真才让 Linux 在服务器领域占了几十年统治地位。Linux 的权限模型继承自 Unix是一种典型的DAC自主访问控制模型。它的核心逻辑很简单每个文件都记录着谁能碰我而这个谁不是直接写人名而是通过UID用户ID和GID组ID来标识。当一个进程想访问某个文件时内核会比对发起这个操作的进程属于哪个用户、哪些组再跟文件身上的权限信息做匹配匹配通过就放行不通过就报错。整个过程在内核层面完成谁也没法绕过。这种设计的巧妙之处在于它虽然是权限模型里最古老最简单的一种但它的简单反而成为优势——规则清晰、执行高效、没有复杂的上下文依赖。Windows 里那种 ACL 权限列表虽然更精细但配置起来复杂得多而且有时候你搞不清到底是什么规则在生效。Linux 这种一个文件的权限就是九个字符的设计一眼看过去就能判断问题出在哪这在排障时是巨大的优势。1.2 权限的三种身份你不是你你是你的身份理解 Linux 权限先要过一道坎在 Linux 眼里你通过用户名登录进来但内核不认用户名只认 UID。用户名是给人看的UID 是给机器认的。你执行任何操作本质上都是带着这个 UID 在跑。每个文件都关联着三种身份分别用三个字母表示uuser/owner文件的主人也就是属主。ggroup文件所属的用户组组内的所有成员共享这一组权限。oother既不是属主也不属于属组的人也就是路人。你对一个文件能做什么取决于你在这三种身份里命中哪一个然后就看那个身份对应的权限位给没给够。举个例子你在一个团队里项目文件属于devops组你是这个组的成员那你吃到的就是g那一段的权限u的权限再大也跟你无关。这个命中一个身份后只看对应权限位的逻辑是理解后面所有命令的基础。1.3 用户和组的关系一对多、多对多在 Linux 里用户和组不是简单的一个人属于一个组而是一个用户可以加入多个组。系统里有一个主组primary group的概念用户创建文件时文件默认归属的组就是主组。同时用户可以加入多个附加组supplementary group用来获取额外资源的访问权。这里建议所有初学者先记住一句话权限判断以进程发起者的身份为基准而不是以你当前登录终端窗口的界面为基准。很多人用 sudo 执行命令后以为当前身份变了其实只有那一条命令是以 root 身份跑的其他还是普通用户。这些基础概念不搞清楚后面看权限配置会越看越晕。2. 权限的底层载体文件属性与 inode 信息2.1 ls -l 输出的每一个字符都别放过每次执行ls -l你都会看到类似下面这样的输出-rw-r--r-- 1 root root 220 2024-05-15 10:30 /etc/hostname这串输出里的第一个字段-rw-r--r--就是文件的权限标识一共 10 个字符。第一个字符表示文件类型后面九个字符才是权限位三个一组- rw- r-- r-- │ │ │ │ │ │ │ └── other其他人的权限 │ │ └─────── group属组的权限 │ └──────────── user属主的权限 └──────────────── 文件类型第一位的-表示这是一个普通文件。如果你看到d就是目录l就是符号链接b是块设备c是字符设备。后面九位里r代表读w代表写x代表执行没有权限的位置就是-。2.2 怎么快速读懂一堆权限字符串遇到drwxr-xr-x这种一串东西别死记硬背要按结构拆。拆开是这样的d是目录rwx是属主可读可写可执行r-x是属组可读可执行但不可写最后的r-x是其他人可读可执行但不可写。我把 Linux 里最常见的几种权限组合整理了一下都是日常高频出现的权限字符串数字表示含义典型场景-rw-------600仅属主可读写私钥文件、敏感配置文件-rw-r--r--644属主可读写其他人只读普通配置文件、网页静态文件-rw-rw-r--664属主和属组可读写其他人只读团队协作文件-rwx------700仅属主可读可写可执行私有脚本-rwxr-xr-x755属主全权限其他人可读可执行可执行程序、目录drwxr-xr-x755属主可读可写可进其他人可读可进最常见的用户目录drwxrwxrwt1777所有人可读写进但只能删自己的文件/tmp 目录其中644和755是最常见的两个数字基本覆盖了绝大多数场景。如果你不确定该给什么权限记住这两个值基本不会出大错。2.3 目录权限跟文件权限的区别很多人栽在这里这里必须单独拎出来说因为目录的 r/w/x 跟文件的 r/w/x 含义完全不同这是新手最容易踩坑的地方。文件的r可以读取文件内容。文件的w可以修改文件内容。文件的x可以执行这个文件。目录的r可以列出目录里有什么ls 能看到名字。目录的w可以在目录里创建、删除、重命名文件。目录的x可以进入这个目录cd 进去也是能不能穿过这个目录访问里面文件的钥匙。r和x在目录上经常要配着给。只有r没有x你能ls看到一堆文件名但看不到文件的类型、权限等详细信息也进不去子目录。只有x没有r你能进去但不知道里面有什么除非你恰好知道确切文件名。所以在实际场景里目录几乎都是r-x或rwx成对出现的。一个特别容易被忽视的坑你要访问一个深层路径下的文件你必须对路径上的每一级目录都有x权限。比如你要读/home/alice/data/config.yaml你至少要对/home、/home/alice、/home/alice/data都有执行权限缺一个都不行。就算文件本身的权限是 777只要中间某个目录挡了一道照样拒绝访问。我见过太多人卡在这一步了。3. 权限管理的三大核心命令实操3.1 chmod用数字还是用字母我劝你都要会chmod是 change mode 的缩写专门用来修改权限位。它有两种表达方式一种是数字法一种是符号法。数字法的逻辑是基于二进制位的r的值是 4w是 2x是 1三者之和就是一组权限的数字。比如rwx 421 7r-x 401 5r-- 4。然后按属主、属组、其他三个数字组合起来就是chmod 754 file这样的格式。chmod 754 script.sh # 属主全权限属组读写执行其他人只读执行 chmod 600 ~/.ssh/id_rsa # 私钥必须严格限制权限 chmod 755 /opt/app/bin # 给目录加执行权限方便所有人进出符号法更适合在原有权限基础上做微调。它的格式是谁操作什么权限chmod ux file # 给属主加执行权限 chmod g-w file # 去掉属组的写权限 chmod or file # 把其他人的权限设为只读 chmod ar file # 给所有人加读权限a 代表 all chmod -R urx dir # 递归给目录内的所有文件加读和执行权限我的使用习惯是大范围设置用数字法因为精确小范围调整用符号法因为不易误伤。新手容易犯的错是写chmod -R 777直接把整个目录放开了。这种操作在极少数临时调试场景下可以用但一旦留在生产环境里基本等于给攻击者开了一道门。后面我会专门讲替代方案。3.2 chown把文件还给该有的人chown是 change owner 的缩写改属主和属组的命令。工作里最常见的场景是把某个目录从 root 手里转给指定用户或者统一修改一批文件的属主属组。chown alice file.txt # 把属主改为 alice chown alice:devops file.txt # 同时修改属主为 alice、属组为 devops chown :devops file.txt # 只改属组属主不变 chown -R alice:devops /data/webapps # 递归修改整个目录树有一个细节值得注意chown可以一次既改属主又改属组但只有 root 才能把文件的属主改成别的用户。普通用户就算对自己的文件也只能用chgrp把属组改成自己所在的组不能把属主改成别人。这是系统层面的安全限制为的是防止你把文件甩锅给别人、绕过权限管理。3.3 一个完整案例部署一个 Web 服务的标准权限配置综合运用一下上面的命令。假设我要在一台新服务器上部署一个 Python Web 应用应用使用www-data用户运行代码放在/var/www/myapp。# 创建目录并交给 www-data 用户 mkdir -p /var/www/myapp chown -R www-data:www-data /var/www/myapp # 代码目录权限 750属主全权限属组可读可进其他人不可见 chmod -R 750 /var/www/myapp # 日志目录要给写权限因为运行时要写文件 chmod -R 770 /var/www/myapp/logs # 配置文件里的密钥文件收紧到只有属主能读 chown root:www-data /var/www/myapp/.env chmod 640 /var/www/myapp/.env这套配置的逻辑是代码文件只允许属主改属组www-data 所在组可读可执行外部其他人一律不可见日志目录因为运行时需要写入所以属组也给写权限.env 文件里存着数据库密码之类的敏感信息所以权限收紧到只有 root 本人能改、属组能读。这套思路的核心原则就是只给够用的权限多给一份都是风险。4. 特殊权限位SUID、SGID、Sticky Bit4.1 SUID为什么普通用户能改密码前面说过 Linux 权限是九个字符但这只是常规权限。在特殊场景下还会有第 4 个隐藏的权限位就是SUIDSet User ID。它的作用是当一个可执行文件设置了 SUID 位普通用户运行它时进程的有效身份会自动切换成文件属主而不是运行者本人。最经典的例子是/usr/bin/passwd。普通用户要改自己的密码就必须去写/etc/shadow文件这个文件只有 root 能写。但系统怎么让普通用户改得了密码呢关键就是 passwd 文件带着 SUID 位。你在终端里执行ls -l /usr/bin/passwd # -rwsr-xr-x 1 root root 68208 2024-01-15 /usr/bin/passwd注意属主的执行位不是x而是s这就表示 SUID 已开启。普通用户执行 passwd 时进程会以 root 的身份去写 shadow 文件写完成就退出。权限控制得非常精准我只让你改自己的密码不给你任何其他 root 能力。SUID 的设置方法是chmod us 文件或chmod 4755 文件4 开头的四位数。但我要强烈建议没事别给任何文件加 SUID 位。SUID 意味着所有普通用户运行这个程序时都临时拥有属主的权限如果属主是 root那就等于任何人运行它都有 root 权限。这是典型的提权攻击入口黑客拿下一个低权限账户后第一件事就是找系统里异常的 SUID 文件。4.2 SGID让目录里新建的文件自动继承属组SGIDSet Group ID和 SUID 类似但它作用于组。它对文件的效果是运行该文件时进程临时获得属组的权限。而它更常见的用途是在目录上当一个目录设置了 SGID 位所有在这个目录里新建的文件或子目录属组会自动继承目录的属组而不是创建者的主组。这个特性在团队协作时非常有用。比如devops组的成员在/srv/project目录下各自创建文件如果没有 SGID文件会归属各自的个人主组其他人就没法访问设置了 SGID 就不一样了所有新文件自动归devops组组内成员都能按组权限访问。chmod gs /srv/project # 或用数字27752 表示 SGID看权限字符串的时候属组的执行位变成s就代表 SGID 生效。类似的如果目录原本属组就没有执行权限你会看到大写的S那是无效的 SGID 位得先补上x权限才有意义。4.3 Sticky Bit为什么 /tmp 里删不掉别人的文件/tmp是一个公共目录所有用户都能往里面写临时文件。那问题来了如果所有人都能写那 A 用户不是可以把 B 用户创建的文件删掉吗Linux 的解决办法就是用Sticky Bit粘滞位。当一个目录设置了粘滞位里面的文件只有文件属主、目录属主或者 root 才能删除或重命名其他人就算有写权限也动不了。ls -ld /tmp # drwxrwxrwt 6 root root 4096 2024-05-15 /tmp最后那个t就是 Sticky Bit 的标志。设置方式chmod t /shared/tmp # 或用数字1777在共享目录、上传目录这类多用户都要写、但不能互相删的场景下粘滞位几乎是标配。讲到这里三个特殊权限的数字位可以放在一起记4是 SUID2是 SGID1是 Sticky Bit。所以chmod 4755是带 SUID 的 755chmod 2775是带 SGID 的 775chmod 1777是带粘滞位的 777。5. 扩展权限ACL 与 sudo 的精细化管理5.1 什么时候该用 ACL 而不是改权限位常规的 u/g/o 三段式权限有一个局限它只能给三种身份设置权限。但如果你的需求是让 A 用户能读这个文件让 B 用户能读写这个文件其他人都不允许三段式就搞不定了。这时候要用ACLAccess Control List访问控制列表。ACL 可以理解为在常规权限之外额外给指定用户或指定组单独设定权限。常用命令是setfacl和getfacl。# 给用户 alice 单独设置对某文件的读写权限 setfacl -m u:alice:rw /data/shared/report.txt # 给 devops 组单独设置读执行权限 setfacl -m g:devops:rx /data/shared/ # 查看文件的 ACL 规则 getfacl /data/shared/report.txt # 删除某条 ACL 规则 setfacl -x u:alice /data/shared/report.txt # 清空所有 ACL 规则 setfacl -b /data/shared/report.txt设置 ACL 之后ls -l输出的权限位后面会多一个号。比如-rw-rw----就说明这个文件还有额外的 ACL 规则。这里要提醒一句ACL 虽然灵活但它增加了排障的复杂度。出了问题别只盯着九个权限位看记得用getfacl查一下有没有隐藏的 ACL 规则。我的建议是能用常规权限解决就不用 ACL避免把系统权限搞成一次性迷宫。5.2 sudo 权限管理与 sudoers 文件配置最后说sudo这是 Linux 里做精细化授权最重要的工具之一。它的配置集中在/etc/sudoers文件里用visudo命令编辑这是规范操作直接用 vim 改有语法错误导致系统混乱的风险。# 允许用户 alice 执行所有命令 alice ALL(ALL:ALL) ALL # 允许 devops 组成员以 root 身份执行 systemctl 开头的命令 %devops ALL(root) /usr/bin/systemctl # 允许用户 bob 不用输入密码执行 /bin/systemctl restart nginx bob ALL(ALL) NOPASSWD: /usr/bin/systemctl restart nginxsudoers 文件的核心语法是谁 在哪台机器上(以谁的身份) 能执行什么命令。日常运维中推荐遵循最小化授权的原则能指定命令就指定命令别给ALL能指定服务就指定服务别给全部权限。这看起来麻烦但真出问题的时候sudo 的限制越小事故半径就越小。另外sudo 和 SUID 的区别值得理解sudo 是通过配置文件精确控制谁能以谁的身份执行什么命令SUID 是只要运行这个文件临时获得属主身份。sudo 更精细也更安全所以在现代 Linux 管理实践中sudo是主流方式SUID 的适用场景非常有限。6. 权限故障排查结合实例讲思路6.1 场景一明明文件权限是 777为什么还是 Permission denied之前有个朋友问我我chmod -R 777了目录为什么我的脚本还是提示没权限我让他执行ls -ld看了一下目录的上层路径结果一下就发现问题了——他给的权限是/data/app/script.sh但/data这个目录的权限是700属主是 root而他用普通用户访问。也就是说他根本没权限穿过/data这一层。Linux 的路径访问逻辑是从根目录/一级一级往下走的每一层目录都必须有执行权限任何一层被卡住后面的全都访问不了。这种问题排查起来也简单从根目录开始逐级用ls -ld检查ls -ld / /data /data/app /data/app/script.sh哪一级权限看起来不对优先怀疑它。然后看当前用户对路径上所有父目录的权限是否足够。这个思路比看文件本身的权限能更快定位问题。6.2 场景二挂载 Windows 或移动硬盘后所有文件都是 777有段时间我挂载 U 盘或者 NTFS 格式的移动硬盘因为 U 盘和 NTFS 的格式不支持 Unix 权限位所以系统会在挂载时自动给所有文件一个默认权限。你可能看到所有文件都显示 777怎么改 chmod 都没用。这是文件系统本身不支持权限位导致的不是系统坏了。正确的做法是调整挂载参数mount -t ntfs-3g -o uid1000,gid1000,umask022 /dev/sdb1 /mnt/usbuid和gid指定挂载后文件归属哪个用户和组umask指定文件的默认权限掩码。022的含义是去掉组和其他人的写权限也就是文件默认644、目录默认755。如果你用的是桌面 Linux图形界面下插 U 盘通常会自动处理但服务器环境下手动挂载时就要特别注意这些参数。6.3 场景三服务启动失败日志显示无法写入 PID 文件这种坑我自己踩过不止一次。部署完一个应用systemd 启动直接失败日志提示无法创建 PID 文件。排查步骤是这样# 1. 查看服务以什么用户运行 grep ^User /etc/systemd/system/myapp.service # Usermyapp # 2. 查看目标目录权限 ls -ld /var/run/myapp /var/log/myapp # 3. 检查属主是否匹配 stat -c %U %G /var/run/myapp如果是/var/run下的子目录很多 Linux 发行版重启后会清理导致它重新以 root 创建目录、属主变成 root应用用户反而没权限写。解决方式有两个方向一是启动前让 systemd 自动创建并归属正确的用户二是把 PID 文件配置到应用用户有权限的目录里。排查这类问题的思路说穿了就三步先确认进程是以哪个用户跑的再确认目标路径的属主属组是否匹配最后确认目录里每一级的权限是否放行。7. 养成好习惯权限安全实践总结踩过足够多的坑以后我在实际操作中慢慢沉淀了几个习惯第一ls -l输出里的时间戳可以帮我快速判断文件是否被动过所以权限不对时看一眼文件属主和修改时间很多问题当场就有头绪第二我很少在不知道后果的情况下使用chmod -R 777很多场景用前面说的 SGID 或者 ACL 就能优雅解决问题第三每隔一段时间会用find / -perm -4000 -type f扫一遍有没有异常的 SUID 文件这是检查系统是否被植入后门的常用手段之一。在权限管理这个领域最小权限四个字永远值得反复强调。给少了可能影响业务给多了就是引狼入室。真正熟练的运维不是在出问题时手忙脚乱地chmod 777而是在部署之初就想清楚这个目录谁要读、谁要写、谁要执行然后只给这么多。长期下来系统的稳定性和安全性都会好很多。