URL-адреса CGI, ссылающиеся на самих себя, используют HTTP вместо HTTPS при использовании AWS ELB.

У меня есть приложение Perl HTTPS, которое работает за Elastic Load Balancer (ELB). HTTPS завершается ELB, который затем перенаправляет запросы как HTTP на мои экземпляры.

Проблема в том, что, поскольку доступ к самому экземпляру осуществляется через 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, чтобы определить, что URL-адреса должны использовать http://.

Можно ли каким-то образом изменить переменные среды на уровне Apache или NGINX, чтобы убедить CGI в том, что сайт на самом деле является HTTPS?


person user1751825    schedule 16.08.2016    source источник
comment
Можете ли вы привести пример кода Perl, который использует функцию CGI для создания URL-адреса, ссылающегося на самого себя?   -  person simbabque    schedule 16.08.2016
comment
Он использует SERVER_PROTOCOL. metacpan.org/source/LEEJO/CGI-4.32/lib/ CGI.pm#L3157 — если это всегда работает в мире https, вы можете просто подкласс CGI или обезьянью-патч эту функцию, чтобы всегда возвращать https.   -  person simbabque    schedule 16.08.2016


Ответы (2)


Я нашел относительно простой способ сделать это.

Я просто включил SetEnv HTTPS в конфигурации Apache. Модуль CGI теперь удовлетворен тем, что это HTTPS, поэтому создает соответствующие URL-адреса.

Я установил другие переменные среды, чтобы они совпадали, просто на всякий случай, но похоже, что это HTTPS, который использует CGI.

person user1751825    schedule 16.08.2016

Это часть 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.

person Sinan Ünür    schedule 16.08.2016