为什么 PHP fopen() 函数不适用于 755 和 775 文件夹权限?

Why the PHP fopen() function is not working with 755 and 775 folder permissions?

我正在使用 ACRA (https://github.com/ACRA/acra) 自动将我的 Android 崩溃报告发布到报告服务器。我有一个 PHP 脚本,它使用以下行将日志文件写入测试服务器上的 https://example.com/logs/ 文件夹:

$FileLog = $_SERVER['DOCUMENT_ROOT'] . "/logs/" . $fname;
$HandleLog = fopen($FileLog, 'a');

只有当我服务器上的 logs/ 文件夹具有这些权限时,PHP fopen() 功能才能正常工作:

drwxrwxrwx (777)

我已经尝试了 drwxrwxr-x (775)drwxr-xr-x (755),但 fopen() 功能不起作用。它仅在我使用 drwxrwxrwx (777) 作为 logs/ 文件夹权限时有效。

这对我来说很奇怪,因为我 运行 的 PHP 脚本在我的服务器上,所以当我从我的 PHP 文件执行 fopen($FileLog, 'a') 时服务器,如果 https://example.com/logs/ 是具有 drwxrwxr-x (775) 权限的文件夹,它应该可以正常工作,因为使用 fopen($FileLog, 'a') 的 PHP 脚本也在同一个 https://example.com 服务器上。你有什么关于为什么只有 777 权限有效的提示吗?我知道 Web 服务器的 drwxrwxrwx (777) 权限是禁忌。谢谢。

更新 1:

使用 fopen($FileLog, 'a') 的 PHP 脚本托管在 https://example.com/loggingscript.php 并由我的 Android 应用程序的 ACRA 库 (https://github.com/ACRA/acra) 调用当它崩溃时。

该目录应归运行网络服务器的用户所有。否则,它需要世界写入权限,以便其他用户可以写入它。

这可能类似于 www-dataapache。如果您不确定这是什么,请参阅

Finding out what user Apache is running as?

Barmar 的回答就是解决方案。但为了准确记录我所做的,我在下面写下了我的详细步骤。

运行 # ps aux | egrep '(apache|httpd)' 显示用户 运行 网络服务器是 www-data:

# ps aux | egrep '(apache|httpd)'
www-data  3735  0.0  2.6 273160 12996 ?        S    06:25   0:00 /usr/sbin/apache2 -k start
www-data  3736  0.0  2.6 273148 12892 ?        S    06:25   0:00 /usr/sbin/apache2 -k start
www-data  3738  0.0  2.6 273216 13092 ?        S    06:25   0:00 /usr/sbin/apache2 -k start
www-data  7163  0.0  2.6 273180 12888 ?        S    12:56   0:00 /usr/sbin/apache2 -k start
www-data  7165  0.0  2.6 273176 13000 ?        S    12:56   0:00 /usr/sbin/apache2 -k start
www-data  8209  0.0  2.6 273200 13032 ?        S    14:26   0:00 /usr/sbin/apache2 -k start
www-data  8211  0.0  2.6 273128 12904 ?        S    14:26   0:00 /usr/sbin/apache2 -k start
www-data  8219  0.0  2.6 273128 12896 ?        S    14:26   0:00 /usr/sbin/apache2 -k start
www-data  8221  0.0  3.3 273192 16412 ?        S    14:26   0:00 /usr/sbin/apache2 -k start
www-data  8235  0.0  2.6 273196 13008 ?        S    14:26   0:00 /usr/sbin/apache2 -k start
root     12976  0.0  0.2  13136  1048 pts/0    S+   22:09   0:00 grep -E --color=auto (apache|httpd)
root     29850  0.0  4.7 268240 23488 ?        Ss   Aug07   0:10 /usr/sbin/apache2 -k start

我将该文件夹的所有权从 root 更改为 www-data:

# chown www-data logs/
# chgrp www-data logs/

现在,当我拥有 755 作为我的 logs 文件夹的权限时,一切正常。

虽然通常 Barmar 在这里给出了很好的建议,但在这个场合,我不同意 "The directory should be owned by the user that runs the webserver"。

八进制权限中的每个数字,以及权限字符串中的每个"rwx"都与用户、组和任何其他uid相关联(其中用户和组是文件上的属性)。如果您的 PHP 脚本应该写入日志,那么它需要以任何用户、组或其他身份执行和写入目录的权限。虽然通常网络服务器 uid 应该是专用网络服务器主机上权限最低的帐户(因此通过 "other" 授予访问权限),但情况并非总是如此。例如,如果主机上还有一个电子邮件 MTA,那么更好的解决方案可能是 770,并通过组所有权向网络服务器授予访问权限。将网络服务器 uid 设置为目录的所有者应该始终是一个自动危险信号。

您设置的权限模型应反映对文件的所有访问权限,使所有相关方都能访问文件(网络开发人员、备份软件、日志轮换服务帐户) ...)它还应该限制任何未明确打算访问的人的访问。 OP 没有告诉我们与目录关联的 user/group/这是否可变/谁需要什么访问权限)。

I know drwxrwxrwx (777) permissions for a web server is a no-no

不一定 - 这应该 never 是默认设置,但有时它是网络服务器 uid 可写内容的正确配置。人们对此感到兴奋的原因是,对于权限有问题的人来说,它通常被视为一种快速修复,他们不应提供 PHP 对内容的写入访问权限。

这里还暴露了一个 大规模 安全漏洞(在没有未提及的其他缓解措施的情况下)。限制 PHP 可以写的地方的主要原因是为了防止最终用户注入代码。为了实现攻击,攻击者还必须有一种调用他们放置在您服务器上的代码的方法。通常日志包含用户提供的数据 - 因此允许 PHP 写入数据可以启动攻击的第一阶段。如果数据写在文档根目录中,那么它可以通过浏览器 URL 直接寻址。

OP 将权限更改为 755 并没有减轻这种攻击,并且造成了只有 PHP 代码和 root 用户才能在日志文件创建后删除它们的情况。