我有一个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的Web服务器,它们由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运行脚本时,我得到三个不同的结果:
Unrecognised protocol tcp at /usr/share/perl5/LWP/Protocol/http.pm line 31.
Can't connect to bibbase.org:443 System error at /usr/share/perl5/LWP/Protocol/http.pm line 51.
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
,然后重新启动了服务器。
答案 0 :(得分:4)
SE-Linux denied the TCP connection。
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")
failed inside IO::Socket::IP。那是非常非常不寻常的。发生这种情况的方法之一就是完全拒绝SELinux。
我不是SELinux专家,但是根据RedHat和Gentoo some SELinux aware applications will ignore the global permissive setting的说法,一个人去吧。 RHEL 7 Apache appears to be one of them。似乎在have its own domain which must be set permissive中。
在这三者中,我都可以在命令行上运行脚本并获得预期的结果:
有两个原因,它们都与用户有关。
运行程序时,您将以自己的用户身份运行,并具有自己的配置,权限和环境变量。实际上,您以root
的身份运行它,通常会绕过限制。当它在服务器上运行时,它将以其他用户身份运行,可能是网络服务器用户受到严格限制。
为了进行实际测试,您需要以与Web服务器相同的用户身份运行它。您可以为此使用sudo -u
。例如,如果用户为apache
...
sudo -u apache ./bibbase_proxy2.cgi
顺便说一句 请勿以root用户身份测试软件! 不仅不会给您带来明智的结果,而且如果软件中存在错误,也无法防止任何安全措施它会破坏系统。
第二个问题是#!/usr/bin/env perl
。这意味着要运行PATH
中的任何perl。 PATH
对于不同的用户将有所不同。运行./bibbase_proxy2.cgi
可以在命令行上运行一个Perl,并通过Web服务器运行另一个。
在服务器环境中,使用类似于#!/usr/bin/perl
的Perl硬编码路径。
答案 1 :(得分:1)
我们通过用Python和PHP重写相同的脚本进行了测试。他们两个都显示出错误,将我们引向正确的方向。
Python urllib2
产生了错误
<class 'urllib2.URLError'>: <urlopen error [Errno 16] Device or resource busy>
args = (error(16, 'Device or resource busy'),)
errno = None
filename = None
message = ''
reason = error(16, 'Device or resource busy')
strerror = None
PHP(以CGI运行)甚至无法启动:
[Wed Jul 25 15:24:52.988582 2018] [cgi:error] [pid 10369] [client 172.28.6.200:44387] AH01215: PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/curl.so' - libssh2.so.1: failed to map segment from shared object: Cannot allocate memory in Unknown on line 0
[Wed Jul 25 15:24:52.988980 2018] [cgi:error] [pid 10369] [client 172.28.6.200:44387] AH01215: PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/dba.so' - libtokyocabinet.so.9: failed to map segment from shared object: Cannot allocate memory in Unknown on line 0
---- Similar lines for all extensions. ----
看来RLimitMEM
阻止了对共享内存的访问,而这是打开套接字所必需的。我找不到任何文档,但是删除该行使其可以工作。