
1. 理解Linux权限体系从UGO到特殊位1.1 基础权限模型rwx三个字符背后的工作逻辑刚接触Linux的朋友第一个接触的权限命令大概率是ls -l。看到-rw-r--r--这一串字符时多数人只知道“这是权限”但要问每个字符到底怎么起作用能讲清楚的人不多。这一串字符其实是在用最紧凑的方式描述一个文件的完整访问规则第一个字符表示文件类型后面每三个字符为一组分别代表属主User、属组Group、*其他用户Others*的权限这就是经典的UGO模型。r、w、x三个权限位在文件和目录上的含义完全不同。文件上的r表示可读取文件内容w表示可修改文件内容x表示可执行文件但目录上的r表示可列出目录内容也就是ls能看到文件名w表示可在目录内创建、删除、重命名文件x表示可进入该目录也就是cd需要的最小权限。这里最容易出现误区一个目录只有r权限没有x权限时你用ls能看到文件名但访问文件详细信息或进入目录时会报Permission denied。用生活场景打比方目录权限就像小区门禁——r是能看到楼栋编号列表x是能走进楼里二者缺了任何一个都进不了家门。掌握数字表示法也是基本功。r4、w2、x1三个数字相加得到八进制权限值。644就是属主可读写、属组和其他用户只读755就是属主可读可写可执行、其他人可读可执行。这种表示法在chmod命令里用得极多因为它比符号模式更简洁。实际工作里我习惯先用stat -c %a %n 文件名快速查看文件权限的数字值再决定怎么改这样比对着rwx逐个换算速度快很多。1.2 特殊权限位setuid、setgid、sticky bit用对是利器用错是漏洞除了基础rwxLinux还藏着三个特殊权限位它们不常出现在日常操作里但一旦涉及到系统运行机制、共享目录协作、临时目录安全就绕不开。这三个位分别是setuidSUID八进制4000、setgidSGID八进制2000和sticky bit粘滞位八进制1000。setuid的作用是当用户执行一个设置了SUID位的可执行文件时进程的有效用户ID会变成文件属主而不是当前登录用户。最典型的例子就是passwd命令。普通用户需要修改自己的密码而密码存储在/etc/shadow中这个文件对普通用户是不可读写的。passwd能被普通用户执行的原因就是它设置了SUID位执行瞬间以root身份运行修改完shadow文件后退出。一个反直觉的事实是对shell脚本或解释器脚本设置SUID位通常无效因为Linux内核出于安全考虑会忽略脚本的SUID位只有编译好的二进制程序才能真正生效。这也是为什么很多教程建议慎用SUID更别对自定义脚本开SUID——一旦脚本本身被篡改就相当于给攻击者开了一扇root后门。排查时应定期查看系统中有哪些文件带SUID位find / -perm -4000 -type f 2/dev/nullsetgid位分两种情况作用于文件时执行该文件的进程会临时获得文件属组的权限作用于目录时新创建的文件会自动继承该目录的属组而不是创建者自己的主组。第二种场景在团队协作目录里很常用——比如开发组共用的项目目录设置SGID后不管谁往里放文件文件属组都是dev组配合组权限就能避免“谁创建的谁才能改”的尴尬。sticky bit只对目录有明显效果最典型的例子是/tmp。这个目录任何人都能写文件但设置了粘滞位后用户只能删除自己创建的文件不能动别人的。查看方式是用ls -ld /tmp看到权限末尾是t而不是x。在共享上传目录里如果不想让用户互相删文件可以chmod t /shared/upload这三个特殊位用好了能简化协作流程但用错了就是灾难级的安全隐患。我在巡检脚本里会把管理机上的SUID文件列表做快照对比变化一旦发现异常新增的SUID文件就立刻告警。1.3 umask与默认权限新文件为什么总是644而不是666新创建的普通文件默认权限是644目录是755这个规律很多人都知道但背后的计算逻辑值得讲透。Linux在创建文件时系统会给文件一个“原始权限”文件是666、目录是777然后减去umask的掩码值就得到最终权限。绝大多数发行版默认umask是022所以文件的最终权限是666-022644目录是777-022755。这里有个小坑因为是在“掩码”而不是“减去数值”的层面计算对于具有执行权限的文件直接用减法会算错。执行umask命令查看当前值umask 002可以临时修改。如果希望新文件默认变成640就设umask 027。umask也影响目录的默认权限如果想新目录不让其他用户进入umask设027就够了。umask常在两个地方配置全局配置在/etc/profile和/etc/bash.bashrc针对单个用户的配置在~/.bashrc或~/.profile。作为运维最常改动umask的是web服务器目录或共享目录——比如把上传目录的umask从022改成002配合SGID目录团队协作时新文件就能自动带上组可写权限。改完umask记得重新登录shell再验证有些环境变量在已登录的会话里不会自动生效。2. 用户与组管理权限的主体与归属2.1 新建用户和组的完整流程useradd背后你容易忽略的参数权限管理绕不开用户和组的管理。很多新手创建用户就是一条useradd zhangsan然后passwd zhangsan设密码完事了。但真正规范的流程要考虑更多细节用户的UID、主目录、Shell、密码策略、附加组。创建用户前先规划UID范围。发行版通常普通用户从1000开始分配但如果你要用NFS共享文件或对接其他服务器不同机器上的用户UID不一致会造成文件属主显示混乱——在A机上显示的是zhangsan同步到B机显示的是501。解决办法是给关键用户指定固定UIDuseradd -u 1500 -m -s /bin/bash -d /home/zhangsan zhangsan-m同时创建主目录-s指定默认Shell-d指定主目录路径。如果不想让用户登录系统可以把Shell设成/sbin/nologin这种账户一般给服务进程用比如nginx、mysql这种程序账号。删除用户的坑同样不少。userdel zhangsan只删除用户记录不删除主目录和邮件文件userdel -r zhangsan才会一起删除主目录和邮件池。但在生产环境里我建议先把用户从所有附加组中移除、杀掉该用户的所有进程再执行删除否则可能出现UID已被新用户复用后老用户遗留文件变成新用户属主的情况这种问题排查起来特别隐蔽。实用的检查命令ps -u zhangsan -o pid,cmd groups zhangsan组的管理相对简单。groupadd dev创建组usermod -aG dev zhangsan把用户加入附加组。注意-aappend一定要带上——如果不带-ausermod -G会直接把用户从其他附加组里全部移除只保留当前指定的组这个失误在线上环境我已经见过不止一次。2.2 属主与属组变更chown和chgrp的正确打开方式文件创建后属主和属组默认来自创建者的UID和主组。但实际部署中经常需要把文件移交给其他账户管理最常见的动作就是chown和chgrp。一条命令同时修改属主和属组chown zhangsan:dev /data/project这里冒号前后必须是用户名和组名组名也可以是组ID。如果只改组chown :dev /data/project。如果你不确认目标用户的UID和组是否存在建议先查一下id zhangsan getent passwd zhangsan递归修改目录权限时要特别小心。chown -R zhangsan:dev /data/project会把这个目录下所有子目录和文件都改掉但如果目录里有符号链接-R默认只改符号链接本身而不跟随链接指向的目标文件不同发行版行为略有差异。如果目录树非常庞大比如百万级文件递归操作会很慢建议用find配合-exec定向修改或者在业务低峰期执行。更稳妥的方式是先只修改目录本身的属主再递归修改内部内容分两步避免中途出错导致不可预期。2.3 sudo授权管理给root权限扎一道可控的篱笆直接给用户root密码是管理上的大忌。出了事分不清是谁操作的权限也收不回来。正确的做法是配置sudo授权让用户用自己密码执行特权命令并且可以精确限制命令范围。sudo配置在/etc/sudoers文件里强烈建议不要直接编辑这个文件而是用visudo命令打开——它会做语法检查防止你写错配置把sudo搞坏。常见的授权格式zhangsan ALL(ALL) ALL这行的意思是zhangsan可以在所有主机上以所有用户身份执行所有命令。但实际中我更倾向于最小授权。比如只允许运维人员执行系统服务管理命令ops ALL(ALL) /usr/bin/systemctl, /usr/bin/journalctl这样用户就不能随便执行rm -rf或修改其他配置。若想免密码执行一般用于自动化脚本场景加上NOPASSWD标记ops ALL(ALL) NOPASSWD: /usr/bin/systemctl配置sudoers时还要注意用户能否切换到其他账户。允许sudo -u www执行命令但不允许直接切root可以这样写ops ALL(www) /bin/bash但这一行的安全边界很有限——一旦用户能以bash身份启动交互shell他其实也拿到了该用户的全部能力。所以在生产环境里对所有高权限账sudo操作我建议开启日志记录。RHEL和Debian系列的journald和/var/log/auth.log里都能看到sudo调用记录也可以单独在sudoers里配置日志类型。配好之后务必用sudo -l验证授权生效情况这是在交付给使用方之前必做的检查。3. 高级权限控制与安全加固3.1 ACL访问控制当三组权限位不够用时的通用解法UGO模型只有三组身份但真实场景中经常碰见“同一目录给多个不同角色不同权限”的需求开发人员能读能写测试人员只能读产品经理只能看目录列表。如果用chmod配合附加组去实现得建三个组还得把用户按组重新归类很麻烦。ACLAccess Control List访问控制列表就是给单个文件或目录附加多条权限规则的工具。设置ACL用setfacl查看用getfacl。给用户tom赋予对某文件的读写权限setfacl -m u:tom:rw /data/project/config.yaml给某个组赋予读权限setfacl -m g:dev:r /data/project/config.yaml设置完之后用ls -l看权限位末尾会多出一个号表示这个文件有扩展ACL。注意一旦对文件设置了ACL原先UGO模型里的group权限位会显示为mask值它限制的是所有命名用户、命名组和权限组能拿到的最大权限。改mask用setfacl -m m::rx /data/project/config.yaml目录的默认ACL也很实用。setfacl -m d:u:tom:rw /data/project会让这个目录下新创建的每个文件都自动继承tom的读写ACL不需要再逐一设置。这在多用户协作目录中能省大量重复操作。使用ACL时务必注意两点一是NFS等文件系统需要挂载参数支持ACL检查挂载选项是否包含acl二是ACL对性能有轻微影响文件数量极大时不要滥用。给关键配置文件的ACL列表建议定期备份导出getfacl /etc/nginx/nginx.conf nginx.acl.backup3.2 文件特殊属性chattr和lsattr锁住关键文件有时候权限明明改对了软件却依然报错“Operation not permitted”这通常不是权限问题而是文件被不可变属性锁住了。chattr命令能给文件设置特殊属性其中i表示文件不可修改、不可删除、不可重命名连root都无法改动只有先执行chattr -i解除属性后才能操作。这一招在防护配置文件和脚本被意外覆盖时非常好用。查看属性用lsattrlsattr /etc/passwd /etc/shadow /etc/nginx/nginx.conf典型操作是把关键的配置文件设为只增模式chattr i /etc/nginx/nginx.conf chattr a /var/log/nginx/access.loga表示只能增加内容不能截断删除适合保护日志文件防止被清空。这里要特别提醒chattr在部分文件系统上不可用比如tmpfs、虚拟机的默认磁盘有些情况不支持某些属性用之前先确认文件系统类型df -T查看。同时在生产服务器上批量实施chattr i之前一定要先在测试机演练一遍避免把整个配置文件锁死导致服务起不来。3.3 权限安全排查定期扫描高危权限点权限管理不只是设置完就完事还要长期维护安全基线。我每个月会跑一轮权限安全扫描重点排查四类问题系统中存在属主为root但权限过于宽松的文件、存在对所有用户可写的目录、存在异常新增的SUID文件、用户主目录权限过宽。查找全局可写文件find / -type f -perm -0002 2/dev/null查找目录权限大于755的敏感目录find /etc -type d -perm -ow 2/dev/null列出所有SUID程序find / -perm -4000 -type f 2/dev/null扫描结果应该和预期白名单对比。对于Web服务器上传目录、临时目录这类必须可写的路径只要限制在最小范围就不算风险但如果/etc、/usr/bin这些系统目录下出现可写文件基本可以断定有问题。权限安全巡检这个动作比任何事后弥补措施都管用很多入侵事件的苗头就是从权限配置漏洞开始的。4. 常见故障案例与排查技巧实录4.1 六个高频权限故障的现场排错故障案例排错是掌握权限管理的必经之路。我自己积累了几个高频问题整理成速查表故障表现常见原因排查命令解决方案执行脚本报Permission denied脚本缺少执行权限或文件系统以noexec方式挂载ls -l script.shmount | grep noexecchmod x script.sh或改挂载选项能列表目录但无法进入目录缺少x权限ls -ld /pathchmod x /path修改文件提示Operation not permitted文件被chattr i锁定lsattr /path/filechattr -i /path/file新创建文件属主不是自己目录设置了SGID或使用了ACL默认属主ls -ld /dirgetfacl /dir按需调整SGID或ACLsudo命令提示command not found命令所在目录不在sudo的secure_path中sudo -l查看当前路径在sudoers中调整secure_pathFTP/nginx上传文件后无法覆盖目录属主和权限不匹配进程用户不是目录属主ps -ef | grep nginxls -ld /data调整目录属主为运行用户或修改权限下面挑两个现场案例展开说。案例一某天开发反馈部署脚本执行报错我上机一看ls -l deploy.sh权限是-rw-r--r--属主是root。开发用普通用户执行自然没有x权限。这种问题根因通常是脚本从Windows拷过来或者压缩包解压时权限丢失。解决很简单chmod x后建议在版本库里直接维护可执行位避免每次部署都要手动改一次。案例二项目组共享目录/data/shareA组用户创建的文件B组用户无法修改即使同在一个组。排查后发现目录没有SGID和ACL默认权限新文件的属组是创建者主组而非共享组。修复方案是在目录上设置SGIDchmod gs /data/share setfacl -d -m g:dev:rwx /data/share之后新文件自动继承dev组组内用户也能正常修改。这个案例也说明权限管理不是一次配置一劳永逸架构和人员变动后需要同步检查和调整。4.2 权限排查的思路与工具链权限问题排查最忌讳一条命令一条命令试浪费时间还容易越改越乱。我一般按三层排查顺序走先确认文件和目录的实际权限ls -ld、stat、getfacl三件套再确认执行进程的用户身份ps -ef、id、sudo -l最后确认文件系统层面的限制mount看挂载选项、df -T看文件系统类型。很多“权限不够”的报错实际是上下文不对——比如通过systemd启动的进程工作目录不同或者通过cron执行脚本的PATH环境变量与登录Shell不一致导致脚本里调用的外部命令找不到。这就是为什么排查权限问题同样要关注进程运行环境systemctl cat 服务名能看WorkingDirectory和User设置cron任务则建议在脚本头部显式用绝对路径调用命令。日志是定位权限问题的第一现场。Debian系看/var/log/auth.log、RHEL系看/var/log/secureauditd如果启动了还能用ausearch -m avc查到更细的拒绝记录。别急着改权限先看日志里报拒绝的具体对象和用户信息往往能一次性定位而不是靠猜。4.3 面试和考核中最常问的权限考点权限管理也是Linux面试里的常客把下面几个重点吃透面试基本不会翻车。我看过太多候选人能背出chmod 777的含义但一深问就露馅。第一个必问的是umask计算题。给定umask 022问新建文件权限是多少。多数人能答出644但如果换一个umask 027再问新建文件权限就经常有人算成640答案是640没错但很多人不是算出来的而是猜的。掌握计算方法后这题就稳稳的。第二个考点是SUID在脚本上为什么不生效。这个问题考察的是对内核安全机制的理解。脚本通过解释器执行解释了为什么SUID位无法传播到解释器进程其中涉及的安全考量讲清楚面试官基本就认可你理解了特权提升的边界。第三个考点是sudo配置的坑。比如让你为一个用户配置免密重启Web服务的sudo规则很多人会把重启命令的路径写错或者没注意NOPASSWD要和命令列表写在同一行。稍微延伸一点就是怎么限制用户只能用sudo跑指定的脚本而不能利用脚本里的漏洞获取root shell。这时候解释清楚脚本内部命令要用绝对路径、不要在白名单脚本里使用环境变量等细节会很有说服力。第四个考点偏实战给一个目录设置ACL默认规则要求子目录新文件自动继承指定组的读写权限同时普通用户的进目录权限不受影响。这一题同时考察setfacl -d与mask的配合答上来了基本可以说明ACL部分真的用过。5. 权限规划思路与收尾经验5.1 做好权限规划比会敲命令更重要摸爬滚打久了才明白权限管理的核心不是记住命令而是设计好一套规划。部署一套新系统时我一般先画一张权限矩阵哪些角色需要访问哪些资源、需要什么级别的操作只读、读写、执行、管理员、哪些是高危操作需要审批。有了这张表再落地成用户、组、ACL和sudo规则权限配置才不会乱。例如一个标准的Web项目环境我会拆出四类角色角色主目录可访问目录可执行命令应用部署用户(devops)项目代码目录/data/apps/var/log/nginxsystemctl reload nginxtail应用运行用户(www)无/data/apps根目录上传目录无shell数据库运维(dba)数据库备份目录/data/mysql-backupmysql相关运维命令审计用户(security)日志审计目录/var/log/secure等只读查看这份矩阵最好用文档或表格管理起来和系统配置同步更新。定期做复核比如每季度把线上的实际文件和用户列表导出来和矩阵比对发现偏差就及时调整这比等到权限事故发生了再补救从容得多。5.2 我踩过的几个权限管理的坑最后分享几个自己踩过的坑都是真实教训。第一个坑是chmod -R 777。刚上手时觉得所有权限问题都靠777解决后来被老同事教育了——全局可写权限对目录而言意味着任何人都能删除里面的文件对Web目录这是致命的。我现在的做法是宁可多配ACL也不用777只有极少数临时共享且马上清理的场景才敢放开。第二个坑是chown递归操作符号链接。有一回执行chown -R www:www /data/app结果不小心把/data/app里一个指向/etc的符号链接也递归处理了导致系统关键目录的属主突然变成www很多服务直接哑火。后来我再做递归属主变更时一律先查找目录里的符号链接find /data/app -type l -ls确认没有链接指向系统目录后再操作或者用chown -hR只改链接本身。这个教训让我养成了大操作前先备份、先清单的习惯。第三个坑是sudoers写错格式导致sudo全部失效。那次我手抖把一个用户名写成了组名但没加%前缀保存后才发现系统里所有sudo命令都无法执行。因为是远程连接差一点把自己锁在门外。从那以后我永远用visudo检查通过才退出而且先开一个备用的root会话窗口确认新配置没问题再关。写到这里也很想说权限管理这件事谨慎永远比聪明值钱。