首页 > 解决方案 > LWP 不会在 CGI 脚本中运行

问题描述

我有一个 CGI 脚本来从 BibBase 加载出版物:

#!/usr/bin/perl

use LWP::UserAgent;

my $url = 'https://bibbase.org/show?bib=http://www.example.com/pubs.bib';
my $ua = LWP::UserAgent->new;
my $can_accept = HTTP::Message::decodable;
my $response = $ua->get($url, 'Accept-Encoding' => $can_accept);

print "Content-type: text/html\n\n";
print $response->decoded_content;

(这是从BibBase复制的,但 URL 是硬编码的。)

我有三个运行 RHEL7 和 Apache 2.4 的网络服务器,它们的配置方式与 Puppet 相同。在所有三个上,我都可以在命令行上运行脚本并获得预期的结果:

[root@server1 cgi-bin]# ./bibbase_proxy2.cgi | head
Content-type: text/html

<img src="//bibbase.org/img/ajax-loader.gif" id="spinner" style="display: none;" alt="Loading.." />

<div id="bibbase">

  <script type="text/javascript">
    var bibbase = {
      params: {"bib":"http://www.example.com/pubs.bib","host":"bibbase.org"},

当我尝试使用 CGI 运行脚本时,我得到三个不同的结果:

我找不到三台服务器之间的任何不同之处,我无法弄清楚为什么脚本在命令行上运行良好并且在作为 CGI 运行时不起作用。

我的 selinux 处于许可模式,它正在记录传出的请求,所以我知道脚本可以做到这一点:

type=AVC msg=audit(1532465859.921:331235): avc:  denied  { name_connect } for  pid=161178 comm="perl" dest=80 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:http_port_t:s0 tclass=tcp_socket 

为了测试,我将 selinux 设置为disabled并重新启动了服务器。

标签: perlcgilwp

解决方案


SE-Linux 拒绝 TCP 连接

avc:  denied  { name_connect }

SELinux 对网络的默认访问控制基于分配给 TCP 和 UDP 端口和套接字的标签。例如,TCP 端口 80 标有 http_port_t(和类 tcp_socket)。然后通过 SELinux 访问控制(例如 name_connect 和 name_bind)管理对这个端口的访问。

当应用程序连接到端口时,会检查 name_connect 权限。但是,当应用程序绑定到端口时,会检查 name_bind 权限。

许可模式与否,Perl 的行为就像它被拒绝了 TCP 连接一样。Unrecognised protocol tcp表示getprotobyname("tcp") IO::Socket::IP 内部失败。这是非常非常不寻常的。可能发生的一种方式就是通过 SELinux 拒绝。

我不是 SELinux 专家,但根据 RedHat 和 Gentoo的说法,一些支持 SELinux 的应用程序会忽略全局许可设置并单独执行。RHEL 7 Apache 似乎就是其中之一。它似乎有自己的域,必须设置为 permissive


在所有三个上,我都可以在命令行上运行脚本并获得预期的结果:

有两个原因,它们都与用户有关。

当您运行程序时,您以您自己的用户身份运行您自己的配置、权限和环境变量。事实上,您运行它时root通常会绕过限制。当它在服务器上运行时,它以不同的用户身份运行,可能是受到严格限制的 Web 服务器用户。

为了进行实际测试,您需要以与 Web 服务器相同的用户身份运行它。你可以用sudo -u这个。例如,如果用户是apache...

sudo -u apache ./bibbase_proxy2.cgi

顺便说一句,不要以 root 身份测试软件!它不仅不会给您带来合理的结果,而且如果软件中存在错误,则没有任何安全措施可以防止它破坏您的系统。


第二个问题是#!/usr/bin/env perl。这意味着运行任何 perl 在你的PATH. PATH对于不同的用户会有所不同。Running./bibbase_proxy2.cgi可以在命令行上使用一个 Perl 运行,而通过 Web 服务器运行另一个 Perl。

在服务器环境中,使用 Perl 的硬编码路径,例如#!/usr/bin/perl.


推荐阅读