ARTICLE DETAIL

资讯详情

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

Linux权限管理实战:umask、粘滞位与file命令构建安全协作模型

Linux权限管理实战:umask、粘滞位与file命令构建安全协作模型 第一次在服务器上被Linux权限管理折磨是在给同事创建共享部署目录的时候。同事说“文件明明在我怎么读不了”我排查半天最后发现是目录有读权限却没给执行权限。这种问题在Linux上非常典型权限设计不是把文件属性改大就行而是一套贯穿新建文件、目录共享、特殊场景防护的完整逻辑。这篇帖子想用15分钟的阅读时间把三块最常用的内容讲透umask掩码、file命令对文件的身份识别、粘滞位的防护作用以及怎么把它们组合成一套多人协作时的权限模型。适合刚接触Linux的开发者、运维也适合被chmod 777折腾过的任何朋友。1. 先看懂权限串rwx、数字映射和三个身份1.1 一条权限字符串里藏着哪些信息在Linux里最基本的权限检查场景就是ls -l命令行里输入一次屏幕上会刷出来一串类似-rw-r--r--或者drwxr-xr-x的字符。很多人能背出r代表读、w代表写、x代表执行但真正排查问题的时候还是要一行一行看甚至有人把文件、目录、符号链接的权限混在一起理解结果越查越乱。其实这条字符串可以拆成四段看。第一个字符是文件类型的标识-是普通文件d是目录l是符号链接b是块设备c是字符设备s是socketp是命名管道。后面九个字符分成三组每组三个分别代表文件所有者u、所属组g、其他用户o的权限。比如-rw-r--r--拆开就是所有者u有读写权限所属组g只有读权限其他用户o也只有读权限。这里最容易搞错的是目录权限的语义。目录的r权限是“可以列出目录里有哪些名字”w权限是“可以在目录里创建、删除或重命名条目”x权限是“可以进入这个目录、访问目录里的文件”。很多人给同事开共享目录的时候只给了r和w忘了x结果同事用绝对路径访问里面的文件权限检查直接失败。一个典型的教训就是没有x权限的目录就算有r权限ls也能看到文件名但cd进去会报Permission denied更别说读文件了。1.2 数字权限不是背出来的八进制换算逻辑聊权限计算之前先解决最基础的映射关系。r、w、x三个权限位本质上就是三比特的二进制数r是4100、w是2010、x是1001。把三组权限分别加起来得到的就是八进制权限值比如rwx就是7rw-就是6r-x就是5r--就是4。这套逻辑用来给别人解释权限就很省事。chmod 644 file对应的二进制权限是rw-r--r--所有者能读写组和其他人只能读chmod 755 script对应rwxr-xr-x所有者能完整操作组和其他人可读可执行。我不建议背表因为只要理解了4、2、1的位权关系任何权限组合都能自己推出来。比如你看到一个权限串是-rwxr-x---那数字就是7、5、0也就是750所有者全部权限组读和执行其他人什么都不给。还有一个顺手的查看方式stat -c %a file直接输出八进制权限比如644。如果配合-c %A %a %U:%G %n一次可以看到符号权限、数字权限、所有者和所属组排查权限问题信息量比ls全得多。1.3 用 stat 拿到权限底牌ls的显示是给人看的某些细节会被隐藏。比如一个文件如果配置了ACL访问控制列表ls -l的权限串末尾会多一个号但具体ACL规则要看getfacl再比如可执行文件有特殊的能力位capabilitiesls也看不出来。所以我在查权限问题时默认先跑一遍stat把模式位、属主、属组、最近修改时间、文件大小全部拉出来。stat输出的Mode字段会显示比如0644或0755这种八进制形式这比ls的字符形式更容易做批量处理。如果你写脚本要判断一堆文件的权限是否符合规范直接stat -c %a %n输出然后awk处理就行。权限管理的第一课不是背命令而是知道“哪些信息藏在哪些工具后面”ls只是入口stat是底牌。2. umask的权限减法为什么你新建的文件总是rw-r--r--2.1 umask的计算模型最大默认值减去掩码每次新建文件或目录系统不会凭空给一个权限值而是由一个叫umask的掩码决定。这个掩码定义的是“你要从默认权限里扣掉哪些位”。理解成权限减法最直接目录的基准权限是777普通文件的基准权限是666最终权限等于基准权限减去umask值。比如默认的umask是022那新建目录就是777 - 022 755对应rwxr-xr-x新建文件是666 - 022 644对应rw-r--r--。这正好解释了为什么大多数人新建的文本文件都是644而不是以为的“读写权限全都给”。如果umask改成002新建目录就是775文件是664组内成员可以互相改文件适合团队协作场景。但这里有个非常多人踩过的坑这个减法不是十进制算术而是按位处理的逻辑扣除尤其是对普通文件算术减法往往会误导。举个例子umask设置为033如果按算术减法算666 - 033 633结果不对。正确做法是理解成逐位移除033表示组和其他位的写、执行权限都要去掉所以文件最终是rw-r--r--也就是644目录则是777 - 033 744碰巧和算术减法一致。所以我的经验是不要死记“666减022等于644”这种巧合要记住umask去掉的是“你不希望默认出现的权限位”文件基准没有x所以umask里的x位对文件通常不起作用。2.2 为什么文件和目录的基准权限不一样这里有个很值得思考的问题为什么目录默认是777文件默认是666因为文件刚创建时没人能确定它是不是脚本如果默认给x就会形成一个“可执行权限满天飞”的局面既不安全也容易造成误操作。而目录必须要有x权限才能进入如果目录默认没有x即使有r权限也只能看到一个空壳无法访问里面的内容所以目录的基准权限要给到满。理解了基准权限umask的设计意图就清晰了。umask 022是单机开发场景最常见的设置它保留所有者的完整权限只去掉组和其他人的写权限保证普通人可以读取文件但不允许随便改。umask 027则更严格组只保留读和执行其他人完全没权限适合服务器上运行敏感服务的账号。umask 077最能体现“权限减法”的极端哲学让新建的文件和目录只属于自己其他用户一律无法访问这是很多安全基线里对用户家目录的要求。2.3 改完立刻生效Shell级与全局设置直接在命令行输入umask 027它就只对当前shell会话生效退出重新登录后恢复原来的值。想让某个用户永久生效就把umask 027写进~/.bashrc或者~/.profile如果想让全系统生效可以在/etc/profile.d/下新建一个脚本比如umask.sh在文件里写入判断逻辑例如root账号保持022普通用户默认027。这里有两个容易忽略的坑。第一个是登录Shell和交互式非登录Shell读取的配置文件不同/etc/profile作用于登录Shell~/.bashrc作用于交互式Shell如果你的服务器是通过终端登录的大概率读的是一套组合改完记得重新登录验证一次umask。第二个坑是sudo。很多人以为在自己的bashrc里设了umask后sudo执行的命令也会继承实际上sudo通常会重置umask具体被重置成什么取决于/etc/sudoers里的Defaults umask配置。我遇到过用sudo创建目录目录权限不是预想中的700而是755的情况查了半天就是sudo把umask拉回了022。3. 粘滞位到底防住了什么/tmp目录亲测案例3.1 粘滞位出现的背景共享目录安全漏洞先想一个场景一个目录是777任何人都能在这个目录里创建文件。按照Linux的权限规则删除文件时检查的不是你对这个文件的权限而是你对“这个文件所在的目录”的写权限。也就是说在一个777的目录里哪怕别人的文件权限是600只要目录的写权限是开放的你就能把他的文件删掉或改名。这就是很多临时目录、共享目录的隐患来源。粘滞位sticky bit就是为了堵这个漏洞设计的。它只能作用于目录作用一句话总结就是只有在“当前用户是文件的所有者、目录的所有者、或者root”的情况下才能删除或重命名目录里的文件而不管目录本身的写权限有多开放。最典型的例子就是/tmp。正常发行版上/tmp的权限是drwxrwxrwt最后一个t就是粘滞位。我做个测试用alice在/tmp下创建一个文件alice_test切换到bob用户去删除它系统会提示Operation not permitted。但如果你把/tmp的粘滞位去掉变成普通777bob就能直接删除alice的文件因为这个目录允许任何人写而删除动作只看目录权限。这么一对比粘滞位的价值就很清晰了它让“可以写”和“可以删别人的文件”这两件事变成了两回事。3.2 t/T 的区别与实操设置粘滞位在权限串中会显示在其他人权限的执行位。如果目录的其他人权限带x会显示小写t比如drwxrwxrwt如果目录的其他人权限没有x就会显示大写T比如drwxrwxr-T。看到大写T要警惕那通常意味着目录既设置了粘滞位本身又没有给其他用户执行权限这种目录往往无法正常访问大概率是哪个管理员手滑把x权限去掉之后设了粘滞位。设置方法很简单chmod t /tmp或者用数字法chmod 1777 /tmp。这里的四位数第一位就是特殊权限位的总和4代表setuid2代表setgid1代表sticky可以组合使用。比如chmod 3770 /shared的意思是同时设置setgid和sticky位再给目录770的权限。查看时用ls -ld看符号显示用stat -c %a看数字输出比如1777这种四位数。实战里还有一个常见错误临时限权时对/tmp这种目录执行chmod -R 777 /tmp-R选项把目录下所有文件的权限都改成777虽然粘滞位还在但里面已经变成所有人都能乱写的状态。所以处理共享目录时优先级应该是先理解需求再决定权限模型而不是一个chmod 777顶上去。4. file命令的权限透视五秒识别一个文件的真实身份4.1 file命令的输出字段怎么读file命令不依赖文件扩展名而是读取文件的头部魔法字节识别它的真实类型。输出格式一般是这样$ file app app: ELF 64-bit LSB executable, x86-64, dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux这一段信息量很大先说明它是可执行文件、CPU架构、是动态链接还是静态链接、解释器路径。换成脚本文件输出可能是Bourne-Again shell script, ASCII text executable换成压缩包可能是Zip archive data。日常里最常用的场景就是快速判断一个文件到底是文本、二进制、还是压缩包。有人觉得file跟权限管理没什么关系其实关系非常大。权限管理管的是“这个文件能不能被执行、被谁执行”但没有回答“这个文件到底是什么”。如果只看权限不看类型一个被赋予执行权限的jpg图片、一个伪装成模板文件的ELF二进制、一个藏在/tmp目录里的Python脚本都有可能被放行。所以权限检查和file命令经常要搭配使用先确认身份再确认权限是否合适。file还支持几个实用参数。file -b不输出文件名只输出类型描述适合在脚本里取值file --mime-type输出MIME类型比如text/plain或application/octet-streamfile -L会跟随符号链接识别链接指向的真实文件。排查问题的时候这几个参数组合起来可以省很多事。4.2 权限管理和安全检查中的file实战姿势最实操的组合是find加file。比如想找出/tmp下所有具备执行权限但不是常规二进制文件的异常文件可以用find /tmp -perm /111 -type f -exec file {} \; 2/dev/null这条命令把/tmp下任何带执行权限的普通文件都拎出来过一遍file一眼就能看到有没有可疑脚本或二进制。如果你是网站运维上传目录常常会被人塞奇怪的文件也可以这样检查。find /var/www -type f -name *.php -exec file {} \; | grep -v ASCII\|Unicode\|UTF-8把不符合预期的PHP文件类型单独抓出来。再配合ls -l观察这些文件的属主和权限位比单看扩展名可靠得多。另一个实用技巧是检查符号链接。很多程序在运行时会通过软链接指向真实的配置文件或二进制有时软链接本身没问题但指向的目标权限不对。比如file -L显示目标是一个脚本而你看到软链接本身带执行权限那就需要去检查目标文件的x权限和umask设置。文件扩展名可以骗人权限位可以改但file命令识别的是头部内容这一层身份验证不容易伪装。5. 把前三样组合成安全协作模型共享目录权限设计实战5.1 共享目录设计group所有权 setgid sticky bit 的组合拳单机开发时权限管得松一点无所谓一旦上了团队协作权限设计就变成一门组合艺术。比较好的做法是把相关用户放进同一个用户组然后围绕组来分配权限而不是逐个用户开权限。一个标准的项目共享目录可以这样建。假设三个人alice、bob、carol组成devteam组需要一个共享工作目录sudo groupadd devteam sudo usermod -aG devteam alice sudo usermod -aG devteam bob sudo usermod -aG devteam carol sudo mkdir /srv/devteam sudo chown root:devteam /srv/devteam sudo chmod 3770 /srv/devteam这条chmod 3770就是前面的组合拳3等setgid位加sticky位770表示所有者和组都有完整读写执行权限其他用户完全不可访问。setgid位的价值在于任何组内成员在这个目录里新建的文件或子目录所属组都会自动变成devteam而不是创建者自己的主组。如果没有setgid新文件会继承创建者的主组可能就被排除在组权限之外了。sticky位则防住了“组内成员误删别人文件”的场景组员可以写所有人的文件但不能删除别人的文件。这里还要和umask配合好。如果团队成员的umask还是默认的022那么新建文件的权限会是644组内其他人只能读不能写协作起来很别扭。正确的做法是让成员把umask设置为002或007这样新建文件和目录的默认权限里组写位是保留的echo umask 002 ~/.bashrc如果要求更严格可以用umask 007让其他人完全没有权限只保留组内协作。这样一套下来目录是drwxrws--T如果设置的是3770文件是-rw-rw----组内自由协作组外完全不可见互相也不能删对方文件。这就是用权限减法搭出来的安全协作模型。5.2 权限减法从0开始加而不是从777开始减很多人在处理权限问题时第一反应是“干脆777”理由是省得后面一堆权限不够的报错。但这种思路是反的真正的安全实践是权限减法从最小权限开始先让业务流程跑通再逐步放开必要的口子。拿一个应用目录举例如果没有明确的共享需求普通用户目录就应该是700配置文件应该是644或640脚本文件应该是755。真实业务需要用户A读取日志那就把日志文件设置成640组设为共同的日志组需要用户B写缓存目录那就建一个专门的缓存目录把属组设为缓存组权限770。每一步都是在做减法永远不要让权限超出“完成当前任务所需的最小范围”。我见过太多事故是从chmod 777开始的。777意味着任何人都可写如果你把这个权限放在一个Web可访问的目录下等于允许任何能触达这个目录的人往里塞文件后果不难想象。权限减法不是说不能给执行权限而是要给得明确谁来执行、在哪执行、执行什么文件都要可控。配合组管理和审计命令比如定期执行find / -perm -0002 -type f查找其他用户可写的文件能很快发现权限管理松动的地方。5.3 一轮15分钟的权限巡检清单最后给一套可以直接照做的巡检清单日常维护时跑一遍基本能覆盖大部分权限风险。第一步找全局可写目录find / -xdev -type d -perm -0002 -ls 2/dev/null这里-perm -0002匹配的是“其他用户可写”的目录。看到结果后判断一下哪些是正常的临时目录、哪些是应用需要的缓存目录其余的全部收紧权限。第二步查/tmp、/var/tmp这两个共享目录里的可执行文件find /tmp /var/tmp -type f -perm /111 -exec file {} \; 2/dev/null用file判断这些可执行文件是不是异常脚本或二进制。第三步检查setuid和setgid文件find / -xdev -type f -perm /6000 -ls 2/dev/null这类文件一旦被写入恶意代码危害比普通可执行文件大得多非必要情况应当移除特殊权限位。第四步检查粘滞位目录find / -xdev -type d -perm /1000 -ls 2/dev/null对照一下哪些目录确实需要粘滞位比如共享临时目录如果发现不认识的目录带着sticky位通常意味着权限模型没有被管理起来。最后检查关键账号的umaskumask sudo -i umask为什么sudo之后还要再执行一次umask因为很多环境里sudo会重设掩码。如果发现sudo出来的默认权限过宽去/etc/sudoers里查Defaults umask条款统一调整。这一套跑下来大约15分钟每次做完我都能发现至少一两个权限过宽的目录。权限管理这件事最难的不是某个命令不会用而是没有形成一套“先最小化、再按需求开放”的检查习惯。把我的实践总结成一句话umask决定新东西的起点chmod决定旧东西的边界粘滞位决定共享空间的底线而file决定你放行的到底是不是你以为的那个文件。
返回列表