2016-08-16 89 views
1

我有一个运行在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_SCHEMESERVER_PROTOCOL确定该网址应该使用http://

有没有什么办法可以在Apache或NGINX级别上使用环境变量来说服CGI该站点实际上是HTTPS?

+0

您可以举一个使用CGI函数创建自引用URL的Perl代码示例吗? – simbabque

+0

它使用'SERVER_PROTOCOL'。 https://metacpan.org/source/LEEJO/CGI-4.32/lib/CGI.pm#L3157 - 如果它总是在https环境中运行,那么您可以继承CGI或猴子补丁,该函数始终返回“https” 。 – simbabque

回答

1

我发现了一个相对简单的方法来做到这一点。

我只是在Apache配置中SetEnv HTTPS'on'。 CGI模块现在认为它是HTTPS,因此可以相应地创建URL。

我设置了其他环境变量来匹配只是为了安全,但它似乎是CGI使用的HTTPS。

1

ThisCGI.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

相关问题