所以,我是 CGI/Perl 的新手,我正在尝试将基于 perl 的 Web 应用程序移动到新服务器。
我的新服务器是 CentOS 7,它运行 Apache HTTPD 2.4.6。
我正在尝试通过 HTTP 请求来获取基本的 Perl CGI 工作。
Web 请求返回“500 内部服务器错误”
错误日志显示“权限被拒绝”:
[Tue May 12 16:56:44.604660 2015] [cgi:error] [pid 12302] [client 10.0.2.2:56693] AH01215: (13)Permission denied: exec of '/var/www/html/cgi-test/first.pl' failed
[Tue May 12 16:56:44.604708 2015] [cgi:error] [pid 12302] [client 10.0.2.2:56693] End of script output before headers: first.pl
我的 CGI 脚本位于 /var/www/html/cgi-test/first.pl
它看起来像这样:
#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "Hello, World.";
在 cgi-test 目录中,权限如下所示:
drwxr-xr-x. 2 root root 21 May 12 16:48 .
drwxr-xr-x. 4 root root 32 May 12 16:48 ..
-r-xr-xr-x. 1 root root 76 May 12 16:48 first.pl
Perl 位于正常位置,并且我认为具有正常权限
[root@localhost cgi-test]# ls -al /usr/bin/perl
-rwxr-xr-x. 2 root root 11400 Mar 6 05:07 /usr/bin/perl
我的 httpd.conf 是默认的。我刚刚添加了以下部分,以便在我的 cgi-test 目录中允许 cgi:
<Directory "/var/www/html/cgi-test">
Options +ExecCGI
AddHandler cgi-script .cgi .pl
</Directory>
为了消除 suexec 导致此问题的可能性,我将其从 /usr/sbin/suexec 移至另一个文件名。
Httpd 以用户“apache”的身份运行,该用户属于“apache”组
[root@localhost cgi-test]# ps -Af | grep httpd
root 12298 1 0 16:56 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
apache 12299 12298 0 16:56 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
apache 12300 12298 0 16:56 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
apache 12301 12298 0 16:56 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
apache 12302 12298 0 16:56 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
apache 12303 12298 0 16:56 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
root 12342 12260 0 17:20 pts/0 00:00:00 grep --color=auto httpd
[root@localhost cgi-test]# groups apache
apache : apache
我已尝试以 apache 身份运行该脚本,它运行正常,没有任何问题。
[root@localhost cgi-test]# su -s /bin/bash apache
bash-4.2$ perl /var/www/html/cgi-test/first.pl
Content-type: text/html
Hello, World.bash-4.2$
大概我碰到了 Apache 的一些安全预防措施。关于这可能是什么,有很多相互矛盾的建议。任何帮助都非常感谢。
答案1
我从你自己的回答中看到,这是一个 SELinux 权限问题,因为尝试在非标准目录中的 apache 内部运行 CGI 脚本。
解决权限问题并保持 SELinux 处于“强制”模式的正确方法是将适当的上下文应用于自定义 CGI 脚本目录中的文件,从而提高服务器的安全性。如果要将其作为永久目录,则应更改 selinux 策略以自动创建具有适当权限的新文件。
您可以使用以下命令检查 cgi-bin 目录的 selinux 策略:
$ semanage fcontext --list | grep cgi-bin
(...)
/var/www/[^/]*/cgi-bin(/.*)? all files system_u:object_r:httpd_sys_script_exec_t:s0
/var/www/html/[^/]*/cgi-bin(/.*)? all files system_u:object_r:httpd_sys_script_exec_t:s0
(...)
这意味着在 apache 的标准 cgi-bin 目录中创建的每个文件都将被自动赋予 SELinux 类型httpd_sys_script_exec_t
并可由 httpd 执行,所以cgi-test
目录中的文件也应该具有这些功能。
笔记:下面显示的示例基于 CentOS/RHEL6,经过最终调整后它应该可以同样适用于 RHEL7。
临时解决方案
你可以简单地用以下命令改变你的 perl 脚本的 SELinux 上下文:
$ chcon -t httpd_sys_script_exec_t /var/www/html/cgi-test/first.pl
使用以下命令检查文件的 SELinux 属性ls -laZ
:
$ ls -laZ /var/www/html/cgi-test/first.pl
-rwxr-xr-x. root root system_u:object_r:httpd_sys_script_exec_t:s0 /var/www/html/cgi-test/first.pl
但是,如果此文件系统上有 SELinux 重新标记操作,属性将恢复为默认值,并且它将再次停止工作。每次添加新的 CGI 脚本时也必须执行此操作。
确定解决方案
您可以通过为自定义 CGI 目录及其所有包含的子目录和文件添加规则来更改 SELinux 策略。
这是通过以下semanage
命令完成的(在policycoreutils-python
RPM 包中可用):
$ semanage fcontext -a -t httpd_sys_script_exec_t "/var/www/html/cgi-test(/.*)?"
这需要一段时间才能运行。更改策略后,自定义目录中创建的任何新文件都将具有新的上下文。对于已经存在的文件,您可以使用以下方式手动应用策略:
$ restorecon -R -v /var/www/html/cgi-test
您可以使用以下命令检查新添加的规则:
$ semanage fcontext --list | grep cgi-test
答案2
如果您无法从 Apache 用户执行 Perl,则会出现此错误。请检查您的用户是否为 Apache 用户,并检查您是否能够从 Perl 脚本中提到的 Perl 位置执行相同的 Perl 脚本。
在我的例子中,我使用的是 /bin/perl,它指向 /root 中的其他 Perl。我的 Apache 用户没有权限执行此 Perl。
您需要进行更改,以便 Apache 用户能够从 /root 位置执行 Perl 或只是更改 Perl 位置。
我改变了 /root Perl 的权限并且它起作用了。
答案3
答案是 SELinux 阻止了对脚本的访问。
谢谢阿尔法迈克维克多提出这个答案。
CentOS 7 上默认启用 SELinux 并阻止 perl / CGI。我使用 /usr/bin/sestatus 确认它已启用
在旧服务器上,SELinux 已被完全禁用。
答案4
确保已在 apache 配置中添加了 ScriptAlias,如下所示
ScriptAlias /cgi-test/ /var/www/html/cgi-test/
还可以尝试将 FollowSymLinks 添加到 Options 指令中。