使用AWS时,CGI自引用URL使用HTTP而不是HTTPS ELB
问题描述:
我有一个运行在Elastic Load Balancer(ELB)后面的Perl HTTPS应用程序。 HTBPS由ELB终止,ELB然后将请求作为HTTP转发给我的实例。使用AWS时,CGI自引用URL使用HTTP而不是HTTPS ELB
问题在于,因为实例本身是通过HTTP访问的,所以当我使用CGI模块生成自引用URL时,它们错误地使用HTTP而不是HTTPS,因此表单POST失败。
GET请求正常,因为它们被重定向,但是任何使用POST的操作都不起作用。
如果我检查我的CGI环境变量,我有以下...
HTTP_X_FORWARDED_PORT = 443
HTTP_X_FORWARDED_PROTO = https
REQUEST_SCHEME = http
SERVER_PROTOCOL = HTTP/1.1
的CGI模块使用可能或REQUEST_SCHEME
以SERVER_PROTOCOL
确定该网址应该使用http://
。
有没有什么办法可以在Apache或NGINX级别上使用环境变量来说服CGI该站点实际上是HTTPS?
答
我发现了一个相对简单的方法来做到这一点。
我只是在Apache配置中SetEnv HTTPS'on'。 CGI模块现在认为它是HTTPS,因此可以相应地创建URL。
我设置了其他环境变量来匹配只是为了安全,但它似乎是CGI使用的HTTPS。
答
This是CGI.pm的一部分,负责确定是否正在使用HTTPS
:
sub https {
my ($self,$parameter) = self_or_CGI(@_);
if (defined($parameter)) {
$parameter =~ tr/-a-z/_A-Z/;
if ($parameter =~ /^HTTPS(?:_|$)/) {
return $ENV{$parameter};
}
return $ENV{"HTTPS_$parameter"};
}
return wantarray
? grep { /^HTTPS(?:_|$)/ } keys %ENV
: $ENV{'HTTPS'};
}
protocol
咨询这个方法的返回值:
return 'https' if uc($self->https()) eq 'ON';
所以,你的SetEnv HTTPS on
解决方案会工作。
但是,如果你想你的程序尊重HTTP_X_FORWARDED_PROTO
,你可以猴子补丁CGI:
#!/usr/bin/env perl
use strict;
use warnings;
use CGI qw();
{
no warnings 'redefine';
my $original_https = \&CGI::https;
*CGI::https = sub {
goto $original_https unless my $proto = $ENV{HTTP_X_FORWARDED_PROTO};
return 'on' if lc($proto) eq 'https';
return 'off';
};
}
my $cgi = CGI->new;
print $cgi->self_url, "\n";
$ HTTP_X_FORWARDED_PROTO=https ./monkey.pl https://localhost:80 $ ./monkey.pl http://localhost
当然,这指出CGI
现在追加端口号,因为它不注意HTTP_X_FORWARDED_PORT
,它可能也会出错。如果我没有弄错,那么你需要猴子补丁virtual_port
。
您可以举一个使用CGI函数创建自引用URL的Perl代码示例吗? – simbabque
它使用'SERVER_PROTOCOL'。 https://metacpan.org/source/LEEJO/CGI-4.32/lib/CGI.pm#L3157 - 如果它总是在https环境中运行,那么您可以继承CGI或猴子补丁,该函数始终返回“https” 。 – simbabque