Skip to content
返回博客
安全

Linux 文件权限完全指南:chmod 755、644 与 777

彻底搞懂 Linux 文件权限:chmod、八进制(755/644/777)与 rwx 的工作原理,含 setuid、umask 与安全默认值,附免费 chmod 计算器。

11 分钟阅读

Linux 文件权限完全指南:chmod 755、644 与 777

Linux 文件权限决定了谁能读取、写入或运行系统上的每一个文件和文件夹。每个对象都有三类用户(属主 owner、一个用户组 group,以及其他所有人 others),每一类各自拥有三个权限位:读取(r)、写入(w)和执行(x)。这样每个文件共有九个权限位。chmod 负责设置它们,而你随处可见的简写形式是八进制(octal):每一类的 rwx 会压缩成一个 0 到 7 的数字(读 4 + 写 2 + 执行 1)。

三种模式几乎覆盖了你会输入的所有情况:

  • 755rwxr-xr-x)——目录和脚本:属主可以修改,其他所有人可以读取和运行。
  • 644rw-r--r--)——普通文件:属主写入,其他所有人读取。
  • 777rwxrwxrwx)——所有人拥有完全访问权限。几乎总是错误的做法;它是一个安全漏洞,而非解决方案。

在免费的 chmod 计算器 里切换任意组合,你就能看到八进制数字、rwx 字符串和精确的命令同步更新。下文会逐一拆解这些数字的含义,以及每种模式各自适合的场景。

30 秒速览 Linux 文件权限

八进制符号表示典型用途
400r--------SSH 私钥,只读
600rw-------私有文件、SSH 密钥、.env
644rw-r--r--网页、配置、大多数文件
700rwx------私有目录(~/.ssh
755rwxr-xr-x脚本、二进制文件、网站目录
775rwxrwxr-x组内共享目录
777rwxrwxrwx所有人、所有权限——避免使用
1777rwxrwxrwt/tmp 这样的共享临时目录

经验法则:文件用 644,目录用 755,再在此基础上收紧。 只有当某个具体功能出问题时才放宽权限,绝不要预先放宽。

权限模型:属主、用户组、其他人

三类用户共享一个文件:属主(通常是创建它的人)、单个用户组,以及其他人,也就是既不是属主、也不属于该用户组的所有账户。每一类都独立拥有读取、写入和执行权限:

  • 读取(r)——查看文件内容,或列出目录中的条目。
  • 写入(w)——修改文件,或在目录中增删条目。
  • 执行(x)——将文件作为程序运行,或进入(cd 进入)目录。

让人栽跟头的地方在于:对目录而言,这些权限位的含义有所不同。r 让你列出名称,w 让你在目录里创建和删除条目,x 让你穿越目录、抵达其下的文件,从而能 cd 进去。你可以对一个目录只有 r 而没有 x,此时能对它运行 ls,但只要一尝试进入就会得到「Permission denied」。这正是目录用 755 而不是 644 的原因。

读懂一行 ls -l

运行 ls -l,每一条目都以一个十字符的块开头:

$ ls -l
-rw-r--r--  1 jack staff  1400 Jul 17 10:00 index.html
drwxr-xr-x  5 jack staff   160 Jul 17 10:00 assets

从左往右读。第一个字符是文件类型,而不是权限:- 是普通文件,d 是目录,l 是符号链接,cb 是设备,p 是命名管道,s 是套接字。接下来的九个字符是三组 rwx:属主、用户组、其他人。所以 -rw-r--r-- 是一个普通文件,属主可读可写(rw-),而用户组和其他人只能读(r-- r--),也就是 644。drwxr-xr-x 则是一个 755 的目录。

有些系统会在这九个权限位后面附加一个标记。末尾的 . 表示存在 SELinux 上下文,+ 意味着有 ACL 在基本权限位之外附加了规则,而在 macOS 上 @ 标记扩展属性。它们都不会改变八进制数字。忽略这个标记,只读那九个字符即可。

八进制记法:755 如何变成 rwxr-xr-x

八进制文件权限之所以奏效,是因为每个权限都是 2 的幂:

  • 读取 = 4
  • 写入 = 2
  • 执行 = 1

把某一类持有的权限位相加,就得到它的数字。rwx 是 4 + 2 + 1 = 7。r-x 是 4 + 1 = 5。r-- 是 4。所以 rwxr-xr-x 按三位一组读出来就是 7 5 5。对 rw-r--r-- 做同样的计算,得到 4 + 2、4、4 → 644。这就是全部诀窍;八进制权限无非就是三个独立的加法。

权限数字 0–7 一览

数字二进制权限
0000无权限
1001仅执行
2010仅写入
3011写入 + 执行
4100仅读取
5101读取 + 执行
6110读取 + 写入
7111读取 + 写入 + 执行

八进制不过是以 8 为基数(base 8)而已,所以每个数字正好打包三个二进制位,不会与下一类重叠。如果你对这种按位换算有些生疏,进制转换器 能展示八进制是如何映射到二进制的,原理和每个权限数字完全一样。

chmod 755 vs 644 vs 777:你真正会输入的模式

下面这个对比直接回答了 chmod 755 vs 644 vs 777 的问题:

八进制符号表示属主用户组其他人典型用途风险
644rw-r--r--读/写普通文件安全默认值
755rwxr-xr-x全部读/执行读/执行目录、脚本安全默认值
600rw-------读/写私有文件、密钥非常安全
700rwx------全部私有目录非常安全
775rwxrwxr-x全部全部读/执行组内共享目录组内可写
777rwxrwxrwx全部全部全部(避免)全局可写

755 和 644 之间只差一个权限位:执行位。目录、脚本和二进制文件需要 x 才能进入或运行,所以它们落在 755。而像 HTML 页面、图片或配置文件这样的普通文件没有理由可执行,所以保持 644。把这两者搞混,正是大多数日常权限错误的根源。

为什么 777 危险。 它把写入权限交给了机器上的每一个账户,包括被攻破的服务账户或被劫持的 Web 进程。全局可写的网站根目录是网站被篡改或被注入恶意软件的教科书式途径,因为任何能访问到它的人都能覆盖你的代码。当某个论坛帖子叫你 chmod 777 某个东西「好让它跑起来」时,真正的问题几乎总是归属权(ownership),下文会讲到。

1777 这个例外。 /tmp 是特意设为全局可写的,但带有一道防护。模式 1777 加上了粘滞位(sticky bit),它让所有人都能创建文件,同时阻止用户删除或重命名不属于自己的文件。这就是为什么共享临时目录用 1777 是安全的,而用纯粹的 777 则绝不安全。在 chmod 计算器 里输入 777,风险面板会立即标记出来,而 1777 则会被识别为标准的共享目录模式。

数字模式 vs 符号模式

chmod 有两种方式来设置同样的权限位。

**数字(绝对)**模式陈述完整的结果。chmod 755 file 会把全部九个权限位设为 rwxr-xr-x,无论之前是什么。这正是你在脚本和部署中想要的,因为你要强制达到一个已知良好的状态。

**符号(相对)**模式描述的是一次变更。chmod u+x file 只翻转一个权限位(为属主添加执行权限),其余一律不动。chmod u=rwx,go=rx file 则显式设置整类用户。符号模式适合一次性的调整——在这种场合重新陈述整个模式就太啰嗦了。

# Numeric: overwrite the whole mode
$ chmod 644 report.txt

# Symbolic: change only what you name
$ chmod u+x deploy.sh        # add execute for the owner
$ chmod go-w shared.conf     # remove write from group and others
$ chmod u=rw,go=r notes.md   # set each class explicitly → 644

符号模式有一个陷阱:不指定用户类的 chmod +x 会被你的 umask 过滤。 在常见的 umask 022 下,chmod +x script.sh 为所有人添加执行权限,所以它等同于 chmod a+x。而在像 077 这样更严格的 umask 下,它只影响属主。当你想要一个确定的结果时,请指明用户类:u+x 只针对属主,a+x 针对所有人。

特殊权限:setuid、setgid 与粘滞位

在九个标准权限位之外,还有一个位于最前面的第四个八进制数字,它承载着三种特殊模式:setuid、setgid 和粘滞位:

  • setuid = 4000——程序以文件属主的权限运行,而非调用者的权限。这正是归 root 所有的 passwd 能让普通用户更新 root 拥有的密码数据库的原理。
  • setgid = 2000——对用户组是同样的道理。在目录上,它还会让新建文件继承该目录的用户组,从而使共享项目的组归属保持一致。
  • 粘滞位 = 1000——在共享目录上限制删除,使用户只能移除自己的文件。1777 的 /tmp 就是最经典的例子。
$ chmod 4755 /usr/local/bin/mytool   # setuid
$ chmod 2775 /srv/shared             # setgid on a shared dir
$ chmod 1777 /tmp                     # sticky bit
$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 59976 Jul 17 10:00 /usr/bin/passwd

s/S 与 t/T 的大小写规则

ls -l 中,特殊权限位复用了执行位的位置,而大小写会告诉你执行位是否也被设置。小写的 s(setuid/setgid)或 t(粘滞)意味着特殊位执行位都开启,这是正常情况。大写的 ST 意味着特殊位已设置但执行位没有开启,这通常是个错误,因为不可执行文件上的特殊位起不到任何有用的作用。

对比 rwsr-xr-x(4755,setuid 带执行位,正确)和 rwSr--r--(4644,setuid 不带执行位,可疑)。每当你看到大写的 ST,都要检查是不是有人不小心丢掉了执行位。

没人提及的 GNU 目录陷阱

有一个几乎每篇教程都搞错的平台差异。在 Linux(GNU coreutils) 上,数字形式的 chmod 755 dir 不会清除该目录上已有的 setuid 或 setgid 位,而是保留它。如果一个目录已经是 2755(setgid),你运行 chmod 755 指望从头开始,setgid 位却会保留下来,这个目录实际上仍然是 2755。

要真正清除它,就得写明确:

$ chmod 00755 dir      # five-digit form zeroes the special digit
$ chmod =755 dir       # = clears every bit not listed
$ chmod u-s,g-s dir    # remove setuid and setgid by name

BSD 和 macOS 则恰恰相反:数字形式的 chmod 755 默认会清除特殊位。所以一个用 chmod -R 755「重置」权限的部署脚本,在 Mac 笔记本上和在 Linux 服务器上的行为并不相同。这种保留行为记录在 GNU coreutils 手册 中;拿不准的时候,就用五位数字形式或 u-s,g-s 形式,这样在任何地方结果都一致。

umask:新建文件会得到什么权限

你很少会手动对每个文件都 chmod;大多数文件的权限是在创建时确定的,而决定它的正是 umask。umask 是一组要关闭的权限位。新建文件从基数 666 开始,新建目录从 777 开始,然后 umask 把相应的位屏蔽掉:

effective mode = base & ~umask

文件从 666 而不是 777 开始,是因为一个全新的文件默认就不该是可执行的。那个执行位是通过 chmod +x 有意添加的。

umask新建文件新建目录含义
022644755默认值——其他人可读,不可写
077600700仅属主私有
002664775组内协作

手动算一遍默认的 022:666 & ~022 = 666 & 755 = 644,而 777 & ~022 = 755。用 umask 查看你当前的值;在任何东西都不该被组或其他人读取的机器上,用 umask 077 设置会话默认值即可。

chmod vs chown:权限 vs 归属

chmodchown 回答的是不同的问题。chmod 改变属主、用户组和其他人能做什么:也就是权限位。chown 改变属主和用户组到底是谁。 动辄用 777,往往是一个披着权限外衣的归属问题。

经典案例:一个以 www-data 身份运行的 Web 服务器无法写入它的上传目录。chmod 777 通过让全世界都能写来使错误消失,却留下了一个漏洞。正确的修复方式是把归属权分配给需要它的进程:

# Wrong: opens the directory to every account on the box
$ sudo chmod -R 777 /var/www/uploads

# Right: give it to the web user, keep a tight mode
$ sudo chown -R www-data:www-data /var/www/uploads
$ sudo find /var/www/uploads -type d -exec chmod 755 {} +
$ sudo find /var/www/uploads -type f -exec chmod 644 {} +

当某个东西意外地无法读取时,诊断顺序是:先运行 ls -l它归谁所有,其次解码权限模式,然后再决定修复办法是 chownchmod,还是把某个用户加入某个组。

正确地递归设置权限

一刀切的 chmod -R 755 . 会把每一个普通文件都标记为可执行,这往好里说是噪音,往坏里说是潜在的风险。应该改为按类型递归:

$ find . -type d -exec chmod 755 {} +   # directories → 755
$ find . -type f -exec chmod 644 {} +   # files → 644

GNU 的 chmod 提供了一个用大写 X 的单行快捷方式,它只为目录以及已经带有执行位的文件添加执行权限:

$ chmod -R u+rwX,go+rX .

chmod 计算器 会为你选定的任意模式生成「仅目录」和「仅文件」的 find 命令,这样你就能直接复制正确的分拆写法,而不必退而求其次用一个简单的 -R

Linux 文件权限最佳实践

  • 授予能用的最小权限。 从最紧的模式起步,只放开出问题的部分。每一个多余的写入位都是攻击面。
  • 默认让 644 的文件位于 755 的目录之中。 这个搭配几乎适用于每一个网站根目录和代码仓库检出。普通文件很少需要执行位;而目录总是需要。
  • 绝不要在服务器能触及的任何东西上留下 777。 如果确实有多个账户必须写入,就用一个共享用户组配合 775 或 2775(setgid 保持组归属一致),而不是把权限对全世界敞开。
  • 让 SSH 私钥保持 600,一旦定稿就用 400。 OpenSSH 会直接拒绝可被组或全局读取的私钥。关于密钥文件的确切要求,参见 OpenSSH 手册。公钥和 authorized_keys 用 644 就没问题。
  • 把文件权限与其他控制手段叠加使用。 权限是基础;当某个文件夹需要登录时,就用 htpasswd 生成器 生成的基本认证(basic auth)与之配合,把文件权限当作整体安全的一环。更完整的做法见我们的 Web 安全最佳实践 指南。

常见问题

drwxr-xr-x 开头的 dl 是什么意思?

ls -l 一行中的第一个字符是文件类型,而不是权限。d 标记目录,l 标记符号链接,- 标记普通文件,cb 标记设备,p 标记命名管道,s 标记套接字。只有它后面的九个字符才编码了实际的读取、写入和执行位。

权限中小写 s 和大写 S 有什么区别?

小写 s 和大写 S 都表示 setuid 或 setgid 位已设置。小写 s 意味着执行位已设置,这是正常工作的情况。大写 S 意味着特殊位开启但执行位关闭(例如 4644),这几乎总是一种配置错误,因为没有执行位的特殊位毫无意义。

umask 是什么,它如何决定默认权限?

umask 是创建文件时被关闭的那组权限位。新建文件从基数 666 开始,目录从 777 开始,然后 effective = base & ~umask 移除被屏蔽的位。默认值 022 得到 644 的文件和 755 的目录;运行 umask 查看你自己的值,或用 umask 077 得到更私密的默认值。

我什么时候该用 400 或 700 而不是 644 或 755?

当一个文件或目录必须保持完全私密时,就用 400 或 700。400(r--------)是一个只读的私有文件,非常适合一个你永不再编辑的、已定稿的 SSH 私钥。700(rwx------)是一个只有属主才能进入的目录,比如 ~/.ssh~/.gnupg。与 644 和 755 不同,它们不给其他任何人授予任何权限。

为什么我能列出一个目录却不能 cd 进去?

目录权限把「列出」和「穿越」分开了:r 位让你列出名称,x 位让你进入。一个有 r 但没有 x 的目录(也就是 644 的目录),在 ls 下能显示其中的名称,却会挡住 cd 以及对内部文件的任何访问。添加执行位(改成 755)就能让它可进入。

macOS 上的文件权限和 Linux 上的一样吗?

在两者上,文件权限共享相同的核心 rwx 和八进制模型,因为它们都遵循 POSIX,但细节有别。BSD 和 macOS 在执行数字形式的 chmod 时默认会清除目录的 setuid/setgid,而 Linux 会保留。读取权限模式的方式也不同:Linux 上用 stat -c '%a' file,macOS 上用 stat -f '%Lp' file,而且 macOS 还额外有 ACL 和文件标志(file flags)。

我能不用命令行就修改文件权限吗?

你可以不用终端就计算和解码权限。免费的 chmod 计算器 让你勾选权限矩阵、输入八进制值,或粘贴一行 ls -l,然后把精确的 chmod 命令复制回来。但要把它应用到真实的文件上,仍然需要在服务器上执行那条命令,或者使用一个暴露了权限字段的 GUI 或 FTP 客户端。

标签: linux chmod file-permissions permissions security