perl - 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 运行脚本时,我得到三个不同的结果:
- 服务器1
Unrecognised protocol tcp at /usr/share/perl5/LWP/Protocol/http.pm line 31.
- 服务器2
Can't connect to bibbase.org:443 System error at /usr/share/perl5/LWP/Protocol/http.pm line 51.
- Server3
没有 http 输出,错误日志显示AH01215: Out of memory!
。
我找不到三台服务器之间的任何不同之处,我无法弄清楚为什么脚本在命令行上运行良好并且在作为 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
并重新启动了服务器。
解决方案
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
.
推荐阅读
- php - Symfony 5.1:使用实体用户提供者的 LDAP 身份验证
- r - 如何使用 grid.arrange 更改绘图的大小
- excel - 如果已经存在,则覆盖正在发送到表的数据?
- gradle - 如何构建可执行的 micronaut jar
- c# - 结构中的 C# 8 的不可为空的引用字段
- c++ - 用于内联映射初始化的动态 atexit 析构函数崩溃
- android - Android onCreate 方法是静态上下文吗?
- javascript - CSS:如何设置 HTML5 输入范围的样式以在拇指之前具有不同的背景颜色和宽度?
- c# - 尝试 xUnit 测试时未将对象引用设置为对象的实例
- swift - 如何允许用户将文件保存到特定目录并在 macOS 应用程序中指定文件名?