ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux 文件权限完全指南:从 chmod、ACL 到 sudo 提权实战

Linux 文件权限完全指南:从 chmod、ACL 到 sudo 提权实战 你盯着终端里那行Permission denied愣神的时候就知道 Linux 文件权限这个东西真不是面试题里背两句chmod 755就能糊弄过去的。作为天天跟服务器、嵌入式设备、脚本打交道的运维和开发权限系统可以说是 Linux 安全模型的基石同时也是坑最多的环节之一——本地文件删不掉、脚本突然没权限、别的用户能读你配置文件、跑起来服务就是启动失败十有八九都是权限在背后捣鬼。这篇文章不是把chmod的手册页给你翻译一遍而是把权限这套规则从设计原理到实操坑位完整梳理出来覆盖基础权限、归属变更、umask、特殊权限位、ACL、sudo 提权和常见故障排查让你看完之后不仅会改权限还知道为什么要这么改万一出事也知道从哪儿查起。1. 权限的本质三类身份与三个开关的组合游戏1.1 别急着敲命令先看懂 Linux 在问“你是谁”Linux 文件权限的核心并不复杂它本质上是一个这样的问题当进程访问一个文件时内核如何判断该不该放行答案不是看心情而是看三组信息——文件的所有者owner、所属组group、以及其他所有人others。这就是我们常说的u、g、o三组身份。我第一次带新人时他们会问为什么我已经用root登录了删文件还是会提示权限不够这时候就得先讲明白一个关键点Linux 的权限校验是基于进程的有效身份effective user id来判断的而不是你感觉上是谁。你在终端敲命令shell 进程带着你的 uid你su切换到 rootuid 变了权限校验也随之变化。如果文件 owner 是 root 但权限是600其他用户即使有密码登录了系统也只能干瞪眼。这套设计的底层逻辑是身份隔离。也就是说权限表达式真正控制的是三类主体对文件的三类操作读r、写w、执行x。文件与目录对r/w/x的解读完全不同这也是很多误操作和看起来没权限问题的根源对普通文件r代表能读取内容w代表能修改内容注意能不能删除由所在目录的写权限决定x代表能作为程序执行。对目录r代表能列出目录里的文件名w代表能在目录里创建、删除、重命名文件x代表能穿越这个目录即是否可以cd进入并使用其中的文件。这就是为什么很多新手chmod 777给目录后发现还是进不去——因为只给了r少了x。目录没有执行权限你连cd都进不去更别说读写里面的文件了。这套目录权限决定能否操作目录项的机制是理解整个 Linux 权限模型的第一块拼图。1.2 数字权限的换算不是 421 死记而是二进制开关再来说说大家都爱用的数字模式比如chmod 644、chmod 755。这个 644 到底从哪来的我见过不少同学是死背4 是读、2 是写、1 是执行然后组合相加。够用但不好理解也没法举一反三应对 ACL 和 umask 的计算。我更推荐你把r/w/x看成三个独立的二进制位r对应数值 4二进制100w对应数值 2二进制010x对应数值 1二进制001所以读写就是426二进制110读执行就是415二进制101。把 owner、group、others 三组各用一个数字表示连起来就是755这种形式。这里有个非常重要、但经常被忽略的细节对文件的权限和你是不是文件 owner是两个维度。内核判断时先匹配 uid如果你是 owner就只看 owner 那三位权限否则匹配组看 group 那三位最后兜底看 others。一旦匹配上就不会再往下看其他位了。这意味着即使你在 others 位有rwx但 owner 位只有r你若是 owner就依然只有读权限。理解这点对后面排查为什么我给 someone 加了 ACL 却还是没权限之类的问题非常关键。2. 权限变更实操chmod、chown 与 umask 的完整用法2.1 chmod 的两种姿势字符模式更直白数字模式更利落chmod的字符模式是我们日常用得最多的。语法是chmod [ugoa][-][rwx] 文件。其中u代表 owner、g代表 group、o代表 others、a代表全部三者。举几个我实际用过的场景给脚本加执行权限但只给 owner 加不希望暴露给所有人就写chmod ux script.sh给 Web 目录设置 owner 可读写执行、group 和 others 只读执行可以写chmod urwx,grx,orx /var/www/html。字符模式的优点是有增有减不用重新算数字。比如我只需要从某文件上移除 group 的写权限直接chmod g-w file就完事完全不需要先看一眼现在的数字是多少。数字模式则适合一次性精确设定。chmod 644 file的含义是owner 读写group 和其他人只读。这是绝大多数普通文件的标准配置因为普通文件不需要执行位。而chmod 755是目录或脚本的标准配置owner 全权其他人可读可执行但不能改。这里我必须提一个血泪教训不要什么事都chmod 777。这三个数字看起来省事但等于把文件的所有权限控制全部交给系统上的每一个用户在服务器上这么干基本等于裸奔。正确姿势永远是能少给就少给。还有个大坑是-R递归参数。你想给整个目录树统一权限chmod -R 755 /path的确干脆但如果目录里有可执行脚本、有需要被 PHP-FPM 写入的缓存文件呢一刀切的结果就是某些原本有写权限的程序开始报错。所以我现在的习惯是递归chmod之前先思考目录和文件是否需要不同权限必要时分开处理而不是图省事。2.2 chown 与 chgrp改了拥有者权限才有意义关于权限归属我在项目里最常遇到的场景是新部署的 Web 应用无法写入日志或上传目录。排查一圈十有八九是目录 owner 还是 root而 PHP-FPM 或 Java 进程跑在www-data或者自定义用户下没有写权限自然各种 500。这时候就要用到chown和chgrp。基础用法是chown 用户名 文件——只改 ownerchgrp 组名 文件——只改组。更常用的是合在一起chown 用户:组 文件一条命令把归属全部改掉。递归场景用chown -R 用户:组 /path。这里有个细节chown只有 root 能修改文件的 owner普通用户想把自己文件的 owner 改成别人是没有权限的因为这是内核的安全约束防止你随便把文件甩锅给别人。但是chgrp则有一个例外——如果你是这个文件的 owner同时你也是目标组的成员那么你可以把文件的 group 改成目标组。举例来说文件 owner 是alicealice同时属于developers组那么alice可以执行chgrp developers 文件但不能再把 owner 改成bob。另外一个容易被忽略的点是目录的 owner 变了里面文件的 owner 并不会自动跟着变。chown -R才能递归处理。如果忘了-R你改了目录的归属里面的旧文件依然是原来用户的新用户进去可能还是没权限。这种目录能看到、文件却用不了的奇怪现象我排查过不止一次。2.3 umask为什么你新建的文件总是 644不是 666平时你可能没注意新建一个普通文件默认权限是644新建一个目录默认权限是755。这个默认值是谁定的答案就是umask它像一个反掩码从系统默认权限里扣除对应的权限位。Linux 系统调用创建文件时内核给文件的默认权限是666普通文件没有默认执行位防止创建出莫名奇妙的可执行文件目录的默认权限是777。然后系统会去掉 umask 中标记为 1 的权限位。绝大多数发行版的 root 用户 umask 是022普通用户也是022文件权限666 ~022 644目录权限777 ~022 755所以如果你希望新建的文件默认不让 group 和其他人有任何权限就把 umask 改成077。这在处理包含敏感信息的项目目录时非常有用。我当时是这么处理的给一个存放密钥的目录设置单独脚本启动时执行umask 077之后生成的任何文件都默认只有 owner 可读写省得担心配置文件里的数据库密码泄露。修改 umask 有两种方式直接在当前 shell 执行umask 077只对当前会话生效写进~/.bashrc或~/.profile对登录 shell 全局生效。任务很急、只想一次性生成一个私有文件的时候还可以在命令行前置(umask 077 touch secret_file)子 shell 里改 umask不影响父 shell 环境这是我推荐的干净做法。3. 特殊权限位与 ACL普通权限之外的另一套规则3.1 setuid、setgid 与 sticky bit三个关键的“例外情况”基础权限讲完之后就该说说那三个出现在ls -l里但大多数人不明所以的特殊标志位了s、S、t。它们解决的都是基础权限模型下解决不了的实际问题。先说 setuidSet User ID。这个权限位用数字 4 表示设置后可执行文件在运行时会以文件 owner 的身份运行而不是以执行者的身份运行。最经典的例子就是/usr/bin/passwd。你可以在终端里看一下ls -l /usr/bin/passwd它的权限通常是-rwsr-xr-xowner 位的执行位显示为s。普通用户想修改自己的密码需要写/etc/shadow而 shadow 文件权限是640owner 为 root普通用户根本写不了。但 passwd 程序有 setuid 位运行时就临时变成 root 身份从而可以修改 shadow 文件。这就是为什么你能改自己密码而不需要把 shadow 文件权限松口。setuid 也是安全隐患的重灾区。如果一个 root 拥有的可执行文件带有 setuid 位任何执行它的用户都能临时获得 root 权限这就等同于系统上的一个后门。安全审计时我习惯用一条命令把所有带 setuid/setgid 的可执行文件列出来find / -perm -4000 -o -perm -2000 2/dev/null然后逐个确认保证没有来历不明的程序坐拥提权能力。这里额外提醒一句setuid 只对可执行二进制文件有意义不能设置在脚本上因为内核对脚本的 setuid 处理在各发行版之间有差异可靠性差而且很容易被利用。所以给 .sh 加 setuid 基本属于无用功。再说 setgidSet Group ID。数字表示为 2。它的含义分两种用于可执行文件时运行进程将以文件所属组的身份运行用于目录时则是在该目录下新建的文件会自动继承该目录的组归属。第二种用途在团队协作时非常有用。我之前给一个开发团队搭共享代码目录要求所有在这个目录下创建的文件都属于developers组而不是创建者的主组。只需要执行chown root:developers /srv/shared chmod 2775 /srv/shared这样之后任何人在/srv/shared里新建文件group 都会自动是developers配合目录的 group 写权限所有组员都能改彼此的文件大大省去了手动chgrp的麻烦。最后是 sticky bit粘滞位数字表示为 1。它只对目录有意义目录开启 sticky 后只有文件 owner、目录 owner 和 root 才能删除或重命名目录中的文件即使其他人对该目录有写权限也不行。最常见的就是/tmp权限显示为drwxrwxrwt最后的t就是 sticky bit。你可以想象一下如果/tmp没有 sticky任何用户都能删除别人留在临时目录里的文件这显然无法接受。自己的家目录要不要开大多数情况下不需要但如果是多人共享的协作目录比如/var/www下某个所有人可写的上传目录开 sticky 会让你睡得安稳不少。3.2 ACL 扩展权限给单一用户开小灶的正确姿势常规权限只有 ugo 三组团队大了就发现不够用。比如某个文件属于www-data而你需要让alice这个用户也能读又不想让alice加入www-data组——这种细粒度控制传统权限模型做不到需要用 ACLAccess Control List访问控制列表。在多数 Linux 发行版上ACL 不是默认开启的文件系统挂载选项里需要包含acl标志同时需要安装acl工具包。查看文件是否启用了 ACL用ls -l看权限位后面是否有个比如-rw-r-----。具体操作几条命令就搞定# 给 alice 用户设置对 file.txt 的读写权限 setfacl -m u:alice:rw file.txt # 给 developers 组设置对目录的读 执行权限并递归应用到已有文件 setfacl -m g:developers:rx -R /srv/project # 查看 ACL 详情 getfacl file.txt # 删除某个用户的所有 ACL 项 setfacl -x u:alice file.txt # 清空所有 ACL setfacl -b file.txt这里有一个很多老手都会踩的坑ACL 设置后ls -l显示的 group 权限位实际上变成了 ACL 的mask掩码。也就是说你设置g:developers:rwx后如果 mask 只有r-x那 developers 组的实际权限会被压缩成r-x写入操作依然被拒。查询时务必用getfacl查看 mask 字段需要放开就用setfacl -m m::rwx file显式调整。从维护成本角度看ACL 适合做小范围特批大范围的权限架构还是应该靠用户组来划分。因为 ACL 规则多了以后排查到底谁有这个文件的权限会变得很困难——你光看ls -l根本不知道背后还有多少条 ACL 规则挂着。所以我的原则是常规权限用 ugo 管理临时性、单点性需求用 ACL并用getfacl做好记录和清理。4. 权限故障排查与安全加固踩过的坑和最后的提醒4.1 最常见的“权限不足”问题排查思路搞权限的人最头疼的就是Permission denied。这个报错本身只告诉你没权限但没说具体是哪一层的问题。我的排查路径基本固定效率很高第一步用id看一下当前用户的 uid、gid 和附加组列表。很多人以为自己是某个组的成员实际上那个组没在附加组里或者改完组后没重新登录导致会话里的组缓存还是旧的。遇到明明加入组了还是没权限的情况先重新登录或者newgrp一下甚至直接exec su - 用户名让会话完全重建。第二步逐层检查文件路径上的每一级目录。记住我之前说的要访问里面的文件路径上的每个目录都需要x权限。常见场景是主目录/home/alice权限为700你让 nginx 去读/home/alice/public_html/index.htmlnginx 进程在访问时第一层/home/alice就把人家拦住了——目录的x权限都没有后面就算文件权限给 644 也白搭。想要让别人访问你 home 下的内容要么放开x要么把内容放到系统公共目录里如/var/www别跟家目录较劲。第三步检查文件自身的 owner、group 和实际权限位。用ls -l看基础权限用getfacl看 ACL。如果权限什么都没问题但程序还是拒绝访问就考虑是不是 SELinux 或 AppArmor 在拦截查看日志# 查看 SELinux 拒绝记录 ausearch -m avc -ts recent # 或者直接看系统日志 tail -f /var/log/messagesSELinux 导致的问题有个典型特征报错信息说的是Permission denied但实际上 ugo 权限和 ACL 都完全正确。因为强制访问控制MAC会在传统的自主访问控制DAC之外再做一次独立判断。对折腾过的人来说临时用setenforce 0验证是不是 SELinux 的问题是最快的鉴别手段确认是它之后再逐条写策略放行而不是粗暴关闭。4.2 最小权限原则用 755、644、077 构建安全底线说了这么多细节最后回到一个贯穿始终的原则最小权限。每当你要给一个文件或目录设置权限时先问自己三个问题这个文件需要被哪些人读需要被哪些人写需要被执行吗答案永远是从最小集合起步遇到底层逻辑跑不通再逐步放宽。一些我能直接给出的基线建议一般配置文件、代码文件644owner 写其他人只读可执行脚本、二进制755owner 全权其他人可读可执行私钥、密码文件、认证凭据600甚至400目录755如果里面需要写入775或2775加 setgid 配合共享组Web 上传目录775owner 设为 www-data 用户或专门用户绝不交给普通用户写需要多用户协作的目录用setgid 共享组 适当 ACL不要靠777实践中最容易出问题的往往是临时放开之后忘记收回来。所以我现在的习惯是凡是chmod 777的操作一定要在命令旁边注释醒目标记凡是调试完的 ACL立刻清理。生产环境里真出安全事故后续排查第一项就是看有没有不该存在的 777 和不该出现的 setuid 文件。4.3 sudo 提权普通人怎么优雅地拿到临时管理员权限最后简单说一下 sudo。它和文件权限的关联在于sudo 本身依赖配置文件/etc/sudoers而这个文件的权限要求是440且 owner 必须为 root。你不能直接改它需要执行visudo来编辑。从权限安全角度说sudo 本质上是精确授权的权限提升——它允许特定用户以特定身份执行特定命令比把 root 密码告诉运维要安全得多。给用户加 sudo 权限的推荐做法是把用户加入wheel组CentOS/RHEL或sudo组Ubuntu例如usermod -aG wheel alice注意-aG的-a是 append追加的意思不加-a会把用户从原有组中全部移除很容易导致用户权限全丢。这种低级错误我见过不止一次务必小心。如果你只希望某人能执行部分命令可以在/etc/sudoers.d/下新建独立文件alice ALL(root) /usr/bin/systemctl restart nginx这样alice只有重启 nginx 的权限其他任何 root 操作都不被允许。别图省事直接写成alice ALL(ALL) ALL那跟把 root 密码交出去没有本质区别。sudo与文件权限还有一个经常被搞混的点sudo是以 root 身份执行命令sudo chmod本质上还是 root 在改权限如果你 root 能改那就一定能改——所谓权限不够在 root 面前基本不成立。所以排查权限问题时可以用sudo -u 指定用户 命令来模拟其他用户执行比如sudo -u www-data cat /var/www/index.php如果这个命令读不了说明文件权限真的有问题如果能读说明问题出在调用方进程的用户上或者 SELinux 上。这招帮我定位过无数次PHP 怎么读不了文件的诡异问题。最后再分享一个实战中积累的小技巧我现在排查毛病时最常用的不是ls -l而是namei -l。它能一条条列出路径上每一层目录的权限自动帮你找出到底卡在哪一级。比如/home/alice/public_html/index.html这个路径执行namei -l /home/alice/public_html/index.html终端会从根目录开始逐层展开权限哪一级没有x一目了然。比起一层层ls比权限这个工具省掉太多时间。权限这个东西折腾过几轮之后你会发现它不复杂但需要敬畏。每个权限位背后都是一条安全边界chmod 777能解决眼前问题但可能埋下更深的雷。养成先分析身份和归属、再精确调整权限的习惯比你多背几十条命令都管用。
返回列表