在计算机文件系统中,不同的文件和目录具有权限,指定了谁以及可以对它们进行读取、写入、修改和访问。这很重要,因为 WordPress 可能需要访问您 wp-content 目录中的文件以启用某些功能。

简要说明

Linux 文件权限主要由三个部分组成——文件或文件夹所有者拥有的权限、拥有该文件或文件夹的组成员拥有的权限,以及其他人对该文件和文件夹进行访问或修改所拥有的权限。这三个权限组件通常用三个数字表示,顺序依次是所有者权限级别、组权限级别和所有人的权限级别。从技术上讲有第四个组件,但这超出了我们需要了解的用于保护 WordPress 的范围。此处不予讨论。

用户、组和其他人各有三种访问类型。它们是读取访问、写入访问和执行访问。读取访问允许您读取文件或目录的内容。写入访问允许您修改文件或目录。执行访问允许您将文件作为程序或脚本运行。

权限模式

 7      5      5
user   group  world
r+w+x  r+x    r+x
4+2+1  4+0+1  4+0+1  = 755

权限模式是通过将以下值相加计算得出的:用户、文件组和所有人。下图展示了计算方法。

  • Read(读取)4 – 允许读取文件
  • Write(写入)2 – 允许写入/修改文件
  • eXecute(执行)1 – 读取/写入/删除/修改/目录
 7      4      4
user   group  world
r+w+x  r      r
4+2+1  4+0+0  4+0+0  = 744

示例权限模式

模式字符串权限解释
0677-rw-rwxrwx所有者仅拥有 rw(6),其他人和组拥有 rwx(7)
0670-rw-rwx—所有者仅拥有 rw,组拥有 rwx,其他人无权限
0666-rw-rw-rw-所有人仅拥有 rw(6)
0607-rw—-rwx所有者仅拥有 rw,组无权限,其他人拥有 rwx
0600-rw——-所有者仅拥有 rw,组和他人无权限
0477-r–rwxrwx所有者仅拥有读取(4),其他人和组拥有 rwx(7)
0470-r–rwx—所有者仅拥有读取,组拥有 rwx,其他人无权限
0407-r—–rwx所有者仅拥有读取,其他人拥有 rwx,组无权限
0444-r–r–r–所有人仅拥有读取(4)
0400-r——–所有者仅拥有读取(4),组和他人无权限(0)

WordPress 权限方案

权限因主机而异,因此本指南仅详述一般原则。它无法涵盖所有情况。本指南适用于运行标准设置的服务器(注意,对于使用"suexec"方法的共享主机,请参阅下文)。

通常,所有文件应由您在 Web 服务器上的用户(ftp)账户拥有,并且该账户应可写入。在共享主机上,文件绝不应由 Web 服务器进程本身拥有(有时这是www、apache或nobody用户)。

任何需要 WordPress 写入访问的文件,其所有者或组所有者应为 WordPress 使用的用户账户(可能与服务器账户不同)。例如,您可能拥有一个允许您与服务器之间 FTP 传输文件的用户账户,但您的服务器本身可能使用单独的用户和单独的组运行,例如dhapache或nobody。如果 WordPress 作为 FTP 账户运行,则该账户需要有写入访问权限,即成为文件的所有者,或属于具有写入访问权限的组。在后一种情况下,这意味着权限设置比默认值更宽松(例如,文件夹为 775 而不是 755,文件为 664 而不是 644)。

WordPress 的文件和文件夹权限对于大多数用户应该是相同的,具体取决于您执行的安装类型以及安装时系统环境的 umask 设置。

注意:如果您是由经验丰富的用户安装的 WordPress,您可能不需要修改文件权限。除非您遇到权限错误问题,或者您想要这样做,否则您可能不应该对此进行更改。

注意:如果您是自行安装 WordPress 的,您可能确实需要修改文件权限。某些文件和目录应通过更严格的权限进行“加固”,特别是 wp-config.php 文件。该文件最初创建时的权限为 644,保留这种状态存在隐患。请参阅安全与加固。

通常,所有核心 WordPress 文件应仅可由您的用户账户(或 httpd 账户,如果不同)写入。(不过,有时多个 ftp 账户用于管理安装,如果所有 ftp 用户都是已知且可信的,即不是共享主机,那么分配组可写可能是合适的。请咨询您的服务器管理员获取更多信息。)但是,如果您使用了 mod_rewrite 永久链接或其他 .htaccess 功能,您应确保 WordPress 也可以写入您的 /.htaccess 文件。

如果您想使用内置的主题编辑器,所有文件都需要组可写。在修改文件权限之前请尝试使用它,它应该可以工作。(如果上传 WordPress 包和插件或主题的是不同的用户,这种情况可能发生。这对于通过管理员安装的插件和主题来说不是问题。当使用不同的 ftp 用户上传文件时需要组可写。在共享主机上,确保组仅包含您信任的用户……apache 用户不应在组中,也不应拥有文件。)

某些插件需要使 /wp-content/ 文件夹可写,但在这些情况下,它们会在安装期间通知您。在某些情况下,这可能要求分配 755 权限。对于 /wp-content/cache/ 也是如此,可能还有 /wp-content/uploads/(如果您正在使用多站点,您可能还需要对 /wp-content/blogs.dir/ 执行此操作)

/wp-content/ 下的其他目录应由所需插件/主题的文档记录。权限会有所不同。

|
|- index.php
|- wp-admin
|   |- wp-admin.css
|- wp-blog-header.php
|- wp-comments-post.php
|- wp-commentsrss2.php
|- wp-config.php
|- wp-content
|   |- cache
|   |- plugins
|   |- themes
|   |- uploads
|- wp-cron.php
|- wp-includes
|- xmlrpc.php

使用 suexec 的共享主机

上述内容可能不适用于使用"suexec"方法运行 PHP 二进制文件的共享主机系统。这是许多 Web 主机使用的一种流行方法。对于这些系统,php 进程作为 php 文件本身的所有者运行,允许配置更简单,并且在共享主机的特定情况下提供更安全的环境。

注意:suexec 方法绝不应在单站服务器配置中使用,它们仅在共享主机的特定情况下更安全。

在这种 suexec 配置中,正确的权限方案很容易理解。

  • 所有文件应由实际用户的账户拥有,而不是用于 httpd 进程的用户账户。
  • 组所有权无关紧要,除非 Web 服务器进程权限检查有特定的组要求。通常并非如此。
  • 所有目录应为 755 或 750。
  • 所有文件应为 644 或 640。例外:wp-config.php 应为 440 或 400,以防止服务器上的其他用户读取它。
  • 任何目录都不应给予 777 权限,即使是上传目录。由于 php 进程作为文件的所有者运行,它获得所有者权限,甚至可以写入 755 目录。

在这种特定类型的设置中,WordPress 将检测到它可以以正确的所有权直接创建文件,因此在升级或安装插件时不会请求 FTP 凭据。

系统管理员用于此设置的流行方法包括:

  • suPHP,通过 php-cgi 运行,自 2013 年以来不再维护。
  • mod_ruid2,Apache 模块,自 2013 年以来不再维护。
  • mpm-itk,Apache 模块。
  • mod_fcgid,一个 Apache 模块和 FastCGI 服务器,具有更广泛的配置。
  • PHP-FPM,一个替代 FastCGI 服务器,带有共享 OPCode,用于 Apache 和 Nginx。

使用 FTP 客户端

FTP 程序(“客户端”)允许您设置远程主机上文件和目录的权限。此功能在程序菜单中通常称为 chmod 或 set permissions。

在WordPress 安装过程中,你可能需要修改的两个文件是索引页(index page)和控制布局的 CSS。以下是修改 index.php 的方法——任何文件的处理过程都是相同的。

在下方的截图中,请查看最后一列——它显示的是权限信息。看起来可能有点令人困惑,但此刻只需留意这些字母的顺序即可。

更改文件权限
初始权限

右键点击"index.php"并选择“文件权限”
将弹出一个对话框。

更改文件权限
修改文件权限

不要担心复选框。只需删除“数值:”后面的内容,然后输入你需要的数字——本例中为 666。然后点击确定。

更改文件权限
权限已修改。

你现在可以看到文件权限已经更改。

显示隐藏文件

默认情况下,大多数FTP 客户端(包括FileZilla)都不会显示隐藏文件,即以点号(.)开头的文件。但在某些时候,你可能需要查看隐藏文件以修改其权限。例如,你可能需要使你的.htaccess文件可写,该文件用于控制固定链接。

要在 FileZilla 中显示隐藏文件,需要从顶部菜单中选择“视图”,然后选择“显示隐藏文件”。屏幕上的文件列表将刷新,之前隐藏的现在应该可见了。

若要令 FileZilla 始终显示隐藏文件,请在“编辑”>“设置”>“远程文件列表”中勾选“始终显示隐藏文件”选项。

在最新版本的 FileZilla 中,“显示隐藏文件”选项已移至“服务器”标签页。请选择“强制显示隐藏文件”。

使用命令行

如果你拥有托管账户的 shell/SSH 访问权限,可以使用chmod来更改文件权限,这是经验用户推荐的方法。在使用chmod之前,建议先阅读一些教程,确保理解它能实现的功能。设置错误的权限可能导致你的网站离线,请务必谨慎操作。

你可以分两步使wp-content目录中的所有文件可写,但在将所有文件和文件夹设为可写之前,应先尝试更安全的替代方案,例如仅修改目录权限。请先依次尝试以下命令,如果不起作用,再使用递归模式,这将使你的主题图片文件也可写。将DIR替换为你想要写入的文件夹名称:

chmod -v 746 DIR
chmod -v 747 DIR
chmod -v 756 DIR
chmod -v 757 DIR
chmod -v 764 DIR
chmod -v 765 DIR
chmod -v 766 DIR
chmod -v 767 DIR

如果上述命令仍无法让你写入,请再次按顺序尝试,这次将-v 替换为-R,这将递归地更改该文件夹内每个文件的权限。如果之后仍然无法写入,你可以尝试 777。

关于 Chmod

chmod是一个 Unix 命令,意为对文件进行"change mode"(更改模式)。-R标志表示将更改应用于wp-content内的所有文件和目录。766 是我们要将目录更改到的模式,意味着该目录对 WordPress 以及系统上的任何其他用户都是可读和可写的。最后,我们指定要修改的目录名称,即wp-content。如果 766 不起作用,可以尝试 777,这将使所有文件和文件夹对所有用户、组和进程都可读、可写且可执行。

如果你使用固定链接,还应更改.htaccess 文件的权限,以确保当你更改设置(如添加新页面、重定向、分类等)时,WordPress 能够更新该文件,因为使用 mod_rewrite 固定链接时需要更新.htaccess 文件。

  1. 进入 WordPress 的主目录
  2. 输入chmod -v 666 .htaccess

注意:从安全角度来看,即使是少量的保护也比完全可写的目录更可取。先从较低的限制性设置开始,如 744,逐步提高权限直到生效。仅在必要时使用 777,并且希望只是临时使用。

777 的风险

此权限问题的核心在于服务器的配置方式。你用于 FTP 或 SSH 登录服务器的用户名,很可能与服务器应用程序本身用于提供页面的用户名不同。

 7      7      7
user   group  world
r+w+x  r+w+x  r+w+x
4+2+1  4+2+1  4+2+1  = 777

通常 Apache 服务器由www-data、dhapache或nobody用户账户“拥有”。这些账户对服务器上的文件只有有限的访问权限,这是有充分原因的。通过将属于你个人账户的文件和文件夹设置为“所有人可写”,你实际上就是让它们变成了全世界可写。现在,运行你的服务器、提供页面、执行 PHP 解释器等操作的 www-data、dhapache 和 nobody 用户将能够完全访问你的个人账户文件。

这为攻击者通过劫持服务器上的几乎任何进程(也包括你机器上的其他用户)来获取文件提供了途径。因此,在修改机器上的文件权限时应仔细考虑。我从未遇到过需要超过 767 权限的情况,所以当你看到 777 时,请思考是否有必要。

最坏的结果

对文件夹甚至文件使用 777 权限可能导致的最严重后果是:如果恶意攻击者或实体能够上传恶毒文件或修改现有文件以执行代码,他们将完全控制你的博客,包括获取你的数据库信息和密码。

寻找变通方法

通常,无需让自己处于风险之中,就可以利用强大的 WordPress 插件提供的增强功能。请联系插件作者或你的服务器支持团队,请求变通方案。

查找安全的文件权限

.htaccess 文件是由运行服务器的进程所有者访问的文件之一。因此,如果你设置的权限过低,服务器将无法访问该文件并导致错误。这正是找到最安全设置的方法:从过于严格的设置开始,逐步增加权限直到生效。

示例权限设置

以下示例包含一个位于 cgi-bin 目录中的自定义编译的 php-cgi 二进制文件和一个自定义 php.ini文件,用于执行 PHP 脚本。为了防止解释器和php.ini文件在 Web 浏览器中被直接访问,它们受到.htaccess 文件的保护。

默认权限(umask 022)

644 -rw-r--r--  /home/user/wp-config.php
644 -rw-r--r--  /home/user/cgi-bin/.htaccess
644 -rw-r--r--  /home/user/cgi-bin/php.ini
755 -rwxr-xr-x  /home/user/cgi-bin/php.cgi
755 -rwxr-xr-x  /home/user/cgi-bin/php5.cgi

安全权限

600 -rw-------  /home/user/wp-config.php
6**0**4 -rw----r--  /home/user/cgi-bin/.htaccess
6**00** -rw-------  /home/user/cgi-bin/php.ini
7**11** -rwx--x--x  /home/user/cgi-bin/php.cgi
**100** ---x------  /home/user/cgi-bin/php5.cgi

.htaccess 权限

644 > 604 – 移除了允许.htaccess 文件组所有者读取的位。644 通常是.htaccess 文件所需且推荐的权限。

php.ini 权限

644 > 600 – 此前,所有具有服务器访问权限的组和用户都可以访问 php.ini,即使只是从站点请求它。棘手之处在于,由于 php.ini 文件仅由 php.cgi 使用,我们只需要确保 php.cgi 进程有权访问。php.cgi 以与两个文件所有者相同的用户身份运行,因此现在只有该单一用户能够访问此文件。

php.cgi 权限

755 > 711 此文件是一个编译后的 php-cgi 二进制文件,用于替代 mod_php 或托管公司提供的默认 vanilla php。此文件的默认权限为 755。

php5.cgi 权限

755 > 100 – 由于用户账户是运行 php cgi 进程的所有者,其他用户或组不需要访问权限,因此我们禁用除执行权限之外的所有访问权限。这很有趣,因为它确实有效。你可以尝试读取文件、写入文件等,但你对此文件的唯一访问权限是运行 PHP 脚本。作为文件所有者,你随时可以将权限模式改回原样。

$ cat: php5.cgi: Permission denied
./php5.cgi:  Welcome

SELinux

Security Enhanced linux 是一个内核安全模块,它提供机制将进程沙箱化到特定的上下文中。这对于限制网页在操作系统其他部分可执行的操作特别有用。被安全策略拒绝的操作通常很难与常规的文件权限错误区分开来。

selinux 通常安装在 Redhat 系列发行版上(例如 CentOS、Fedora、Scientific、Amazon 等)。

如何确定 selinux 是否是问题所在?

如果您使用的是基于 Debian 的发行版,可能没有问题。

运行以下命令(在基于 rpm 的系统上);

$ rpm -qa | grep selinux
selinux-policy-targeted-3.13.1-166.el7_4.7.noarch
selinux-policy-3.13.1-166.el7_4.7.noarch
libselinux-2.5-11.el7.x86_64
libselinux-python-2.5-11.el7.x86_64
libselinux-utils-2.5-11.el7.x86_64

并检查它是否是权限被拒绝的原因:

$ getenforce
Enforcing

selinux 导致的一个问题是阻止 wp-admin 工具写入 url 重写所需的 `.htaccess` 文件。有几个命令可用于检查此行为:

$ audit2allow -w -a
type=AVC msg=audit(1517275570.388:55362): avc:  denied  { write } for  pid=11831 comm="httpd" path="/var/www/example.org/.htaccess" dev="vda1" ino=67137959 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:httpd_sys_content_t:s0 tclass=file
        Was caused by:
        The boolean httpd_unified was set incorrectly.
        Description:
        Allow httpd to unified

        Allow access by executing:
        # setsebool -P httpd_unified 1

以及

$ ausearch -m avc -c httpd
----
time->Tue Jan 30 01:30:31 2018
type=PROCTITLE msg=audit(1517275831.762:55364): proctitle=2F7573722F7362696E2F6874747064002D44464F524547524F554E44
type=SYSCALL msg=audit(1517275831.762:55364): arch=c000003e syscall=21 success=no exit=-13 a0=55b9c795d268 a1=2 a2=0 a3=1 items=0 ppid=11826 pid=11829 auid=4294967295 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=4294967295 comm="httpd" exe="/usr/sbin/httpd" subj=system_u:system_r:httpd_t:s0 key=(null)
type=AVC msg=audit(1517275831.762:55364): avc:  denied  { write } for  pid=11829 comm="httpd" name="bioactivator.org" dev="vda1" ino=67137958 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:httpd_sys_content_t:s0 tclass=dir
----

您可以暂时禁用 selinux 以确定它是否是问题的原因;

$ setenforce
usage:  setenforce \[ Enforcing | Permissive | 1 | 0 \]