用户目录中的 Apache CGI "End of script output before headers"

Apache CGI in user directory "End of script output before headers"

我知道有一些关于这个主题的问题,但是 none 似乎解决了我的问题。参见 this or this or this

我在 Linux、Fedora21 上,我正在尝试为每个用户目录启用 CGI 脚本。我按照 these 说明进行操作,但没有成功。

我收到错误:

[cgi:error] End of script output before headers: test.cgi

test.cgi是一个可执行的sh文件,包含一个非常简单的脚本:

#!/usr/bin/sh

echo "Content-type: text/plain"
echo ""
echo "Hello"

它具有可执行标志并且在 shell 中运行没有问题。 我也试过 Python: 同样的结果。

我还禁用了 selinux 以防万一。

我也尝试将 debug 级别设置为 Apache 的错误日志,但我得到的只是上述错误之前的 "granted" 权限。

我还配置了 /etc/httpd/conf.d/userdir.conf 文件

<Directory "/home/*/public_html">
    AllowOverride All
    Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
    Require all granted
</Directory>

<Directory /home/*/public_html/cgi-bin/>
    Options ExecCGI FollowSymLinks
    SetHandler cgi-script
    AddHandler cgi-script .cgi .exe .pl .py .vbs
    Require all granted
    AllowOverride All
</Directory>

并重新启动了服务器。没有成功。我觉得一切都很好,我不明白...怎么了??

编辑:

我忘了补充一点,这个问题只是针对每个用户的目录:如果我将相同的脚本移动到 /var/www/cgi-bin 目录,它会按预期工作。

编辑 2:

shell确实存在:

$ ls /usr/bin/sh
/usr/bin/sh

我看到 "End of script output before headers: myscript.py" Python 2.x CGI 脚本的消息 运行 从命令行可以正常工作。

问题是 Web 服务器没有正确执行它,即使它来自 command-line。无论系统返回给服务器的错误消息是什么,它肯定不会通过 CGI headers(例如,"Content-Type: text/html\r\n\r\n")。因此,此失败消息。

对我来说,更正它意味着将 shebang 从:

#!/usr/bin/env python

更system-specific(但可验证):

#!/usr/local/bin/python

也许您遇到了类似的情况。

(FreeBSD 9.x。)

对我来说,当我将 shebang 行 (#!/usr/bin/sh) 更改为 #!/usr/bin/env sh 时它起作用了。我发现来自 What is the preferred Bash shebang? 的任何 shebang 行似乎都有效(但是请注意 shbash 不同,所以如果您想使用 sh 坚持使用它)。

所以这段代码对我有用:

#!/usr/bin/env sh
echo "Content-type: text/plain"
echo ""
echo "Hello"

此外,根据上面提到的 post,/usr/bin/env sh 似乎优于 /bin/sh。我不知道每个目录的东西。

当您尝试从您的 cgi 调用其他 Python 模块方法时,您可能会留下一些 'print' 语句(可能用于调试),有时会出现这种情况。因此,扫描您的代码以查找任何 'print' 语句,有时这很容易解决问题。

只让文件所有者对cgi脚本有写权限,而不是,即-rwxr-xr-x而不是 -rwxrwxr-x.

在用户目录中,组通常是一个个人用户组,无论如何只有用户是其中的成员,但 Apache 似乎对看到 g+w 位感到紧张但给出了一些关于此的虚假错误消息。

我终于解决了这个问题。感谢@JimB,因为在 他指出了 SUEXEC,我不知道(或者直到现在才忽略)。

阅读 suEXEC documentation 后,我明白问题一定出在那里。于是,我看了一下配置:

# suexec -V
 -D AP_DOC_ROOT="/var/www"
 -D AP_GID_MIN=1000
 -D AP_HTTPD_USER="apache"
 -D AP_LOG_SYSLOG
 -D AP_SAFE_PATH="/usr/local/bin:/usr/bin:/bin"
 -D AP_UID_MIN=1000
 -D AP_USERDIR_SUFFIX="public_html"

一切看起来都很好(对我的用户来说 uid/gid 很好,userdir_suffix 很好,等等)。所以我看了一下系统日志:

# journalctl -b | grep "suexec"
May 22 11:43:12 caladan suexec[5397]: uid: (1000/user) gid: (1000/user) cmd: test.cgi
May 22 11:43:12 caladan suexec[5397]: directory is writable by others: (/home/user/public_html/cgi-bin)

那就是问题:我的cgi-bin目录可被其他人写入

我通过简单地将权限更改为 755 来修复。

当我们以旧方式使用打印时会出现此错误。

print 'your test'

应该是Python以后的版本。

print ('your test')

尝试运行以 apache 用户身份运行脚本。

发生这种情况的原因有很多。 @JimB 提到了 shebang 的问题。 @premganz 提到了在写入 Content-Type 字符串之前触发的调试打印语句的问题。在我的例子中,这是一个数据库连接失败。可能是其他问题。

我发现最好的调试方法是 运行 在命令行中以 apache 用户身份直接运行脚本,然后查看它给出的错误。

如何 运行 您的脚本作为 Apache 用户

假设您运行正在使用 apache2,并且 apache 用户是 www-data,并且您的 cgi 脚本是 /myapp/myreport.py - 您可以执行以下操作。

  1. 通过更改其默认值 shell 允许以 www-data 用户身份登录。编辑 /etc/passwd(暂时)

    sudo su - 
    cd /etc
    cp -p passwd passwd.2017-10-22
    
    emacs passwd     # edit file - use your favorite editor
    

    变化:

    www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
    

    收件人:

    www-data:x:33:33:www-data:/var/www:/bin/bash
    
  2. 以 www-data 用户身份登录

    sudo su - www-data
    
  3. 设置任何环境变量。将您的 apache SetEnv 语句转换为导出语句。在我的例子中,我的 apache 配置目录设置有这些 vars set

    SetEnv PYTHONPATH /myapp/lib
    SetEnv VCONF /myapp/conf/prod.yaml
    

    运行 他们是

    export PYTHONPATH=/myapp/lib
    export VCONF=/myapp/conf/prod.yaml
    
  4. 然后试试你的cgi脚本

    cd /myapp
    ./myreport.py
    
  5. 您应该看到 Apache 遇到的任何错误。修复它们。

  6. 将 www-data 用户的默认 shell 设置回 /usr/sbin/nologin

我在 userdir 中执行 python cgi 时遇到问题。

/var/log/httpd/error_log 显示:

[Fri Apr 26 13:09:41.840285 2019] [cgi:error] [pid 25421] [client 98.234.206.134:60837] End of script output before headers: index.cgi

在 URL 中调用的用户是 doug,用户 42,组 42

我依稀记得 suexec 在为 1000 以下的组或用户执行 cgi 脚本时遇到问题。

所以我创建了一个名为 user1k 的新组 as 1000。 然后我做了

adduser -g 1000 -u 1000 dwg
chmod 755 /home/dwg
mkdir /home/dwg/public_html

然后我将我的 python cgi 脚本放到这个目录中。

现在组和用户 >= 1000,脚本开始正确执行。 我不确定是用户还是组解决了问题,但是改变它们肯定解决了问题。

注意:问题是用户 ID 低于 1000。 所以使 userdir cgi executee 的 userID > 999.

这是 man suexec 输出的摘录。

Is the target userid ABOVE the minimum ID number? The minimum user ID number is specified during configuration. This allows you to set the lowest possible userid that will be allowed to execute CGI/SSI programs. This is useful to block out "system" accounts.

Is the target groupid ABOVE the minimum ID number? The minimum group ID number is specified during configuration. This allows you to set the lowest possible groupid that will be allowed to execute CGI/SSI programs. This is useful to block out "system" groups.

我遇到了同样的问题。我需要这个:

sudo setsebool -P httpd_read_user_content 1

这是我通过查看日志发现的 (journalctl -b) 这告诉我...

SELinux 正在阻止 /usr/bin/python2.7 对目录 public_html.

的搜索访问