Подтвердить что ты не робот

Неверный номер порта, возвращаемый $_SERVER ['server_port']

Сценарий: Я работаю на веб-сервере Apache с некоторым PHP. Я указываю свой браузер на https://my.example.com/test.php, в котором есть следующие строки кода:

<pre>
<?php
print_r($_SERVER);
?>
</pre>

Значение, напечатанное для SERVER_PORT, 80, а не 443. Но если я перейду к https://my.example.com:80/test.php веб-серверу (Apache) barfs (Произошла ошибка во время подключения к my.example.com:80. SSL получил запись, которая превысила максимально допустимую длину. Код ошибки: ssl_error_rx_record_too_long). Если я перейду к https://my.example.com:443/test.php, тогда URL-адрес перенаправляется на https://my.example.com/test.php без ошибок или проблем, кроме того, что мой PHP выдает, что порт сервера равен 80 вместо 443.

Вот соответствующий раздел из файла conf.d/ssl.conf (я удалил то, что, по моему мнению, посторонними директивами и заменил фактический IP-адрес словом IP_ADDRESS):

Listen IP_ADDRESS:443    
<VirtualHost *:443>
        ServerName my.example.com
        ServerAlias my
        DocumentRoot "/path/to/document_root/htdocs"
        Options +Indexes
</VirtualHost>

Вот полная распечатка переменной $_SERVER (с данными моего сервера, отредактированными/измененными на анонимные примеры):

Array
(
    [HTTP_HOST] => my.example.com
    [HTTP_USER_AGENT] => Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11
    [HTTP_ACCEPT] => text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    [HTTP_ACCEPT_LANGUAGE] => en-us,en;q=0.5
    [HTTP_ACCEPT_ENCODING] => gzip,deflate
    [HTTP_ACCEPT_CHARSET] => ISO-8859-1,utf-8;q=0.7,*;q=0.7
    [HTTP_KEEP_ALIVE] => 115
    [HTTP_CONNECTION] => keep-alive
    [HTTP_COOKIE] => PHPSESSID=randomstring_yes_I'm_that_paranoid
    [PATH] => /sbin:/usr/sbin:/bin:/usr/bin
    [SERVER_SIGNATURE] => 
Apache/2.2.3 (Red Hat) Server at my.example.com Port 80


    [SERVER_SOFTWARE] => Apache/2.2.3 (Red Hat)
    [SERVER_NAME] => my.example.com
    [SERVER_ADDR] => IP_ADDRESS_1
    [SERVER_PORT] => 80
    [REMOTE_ADDR] => IP_ADDRESS_2
    [DOCUMENT_ROOT] => /path/to/document_root/htdocs
    [SERVER_ADMIN] => [email protected]
    [SCRIPT_FILENAME] => /path/to/document_root/htdocs/test.php
    [REMOTE_PORT] => 49178
    [GATEWAY_INTERFACE] => CGI/1.1
    [SERVER_PROTOCOL] => HTTP/1.1
    [REQUEST_METHOD] => GET
    [QUERY_STRING] => 
    [REQUEST_URI] => /test.php
    [SCRIPT_NAME] => /test.php
    [PHP_SELF] => /test.php
    [REQUEST_TIME] => 1292273758
)

Как вы можете видеть, SERVER_PORT - 80, а $_SERVER ['HTTPS'] не установлен. Согласно документам PHP, я думал, что он должен быть установлен на непустое значение, если PHP script доступен через HTTPS (что я и делаю).

Любая идея, что происходит? Я просто веб-разработчик - я не управляю этим сервером, но мой администратор сервера сообщает мне, что все работает, но я хотел бы знать, почему $_SERVER ['SERVER_PORT'] возвращает 80 вместо 443 при просмотре URL-адреса HTTPS.

EDIT: Я редактировал приведенный выше пример, чтобы проиллюстрировать мои результаты при печати всей переменной $_SERVER.

РЕДАКТИРОВАТЬ 2: Попытка https://my.example.com:443/test.php, как предложено в комментариях ниже, делает то же самое - SERVER_PORT 80 и HTTPS не задано (в частности, этот URL перенаправляется на https://my.example.com/test.php).

РЕДАКТИРОВАТЬ 3: Хорошо, я опубликовал то, что, по моему мнению, является ответом на это ниже (TL; DR: перемещение директив SSL внутри директивы VirtualHost и изменение этой директивы для ссылки на мой сайт с использованием это IP-адрес, а не подстановочный знак, по-видимому, разрешил проблему).

4b9b3361

Ответ 1

Недавно я столкнулся с одной и той же проблемой, потому что какой-то код, который у меня был, маскировал ту же проблему, мешал мне.

Мой диагноз проблемы таков: Это причуда изменения, внесенного в Apache 2.0. Директива Port больше не является частью директив httpd.conf, по существу разделенных между ServerName и Listen.

Итак, у моего apache httpd.conf(Apache 2.2.23) были эти записи

ServerName myservername.com
Listen: 5150

Тем не менее PHP $ _SERVER ['SERVER_PORT'] возвращал 80 на все запросы, сделанные на порту 5150.

Итак, просматривая документы Apache, я нашел лакомый кусочек о том, что Port является устаревшей директивой и ServerName, вложенной в нее.

Я устанавливаю свою директиву servername следующим образом

ServerName myservername.com:5150
UseCanonicalName On
Listen 5150

и вдруг php script поступает правильно, сообщая _SERVER ['SERVER_PORT'] как 5150.

В качестве альтернативы ваш httpd.conf может читать

ServerName myservername.com
UseCanonicalName Off
Listen 5150

Итак, тогда я выкопал исходный код php (5.3.20) и исходный код apache, пока не нашел источник поведения.

Поведение коренится в (по крайней мере, для исходного кода 2.2.23) в dirOfApacheSource/server/core.c Посмотрите на функцию AP_DECLARE(apr_port_t) ap_get_server_port(const request_rec *r)

Здесь вы увидите, что если ваша директива httpd UseCanonicalName установлена ​​на "On", тогда порт получает синтаксический анализ из директивы ServerName. Если директива ServerName не относится к типу ServerName myserver.com:myport, код case будет извлекать ap_default_port объекта запроса (по умолчанию пользователю apache по умолчанию присвоено значение 80).

Если вы беспокоитесь о том, что вам нужно явно добавить порт в директиву ServerName в httpd.conf, ваш другой выбор - установить UseCanonicalName в "Off", это заставляет код в server/core.c анализировать Запрос URI для извлечения имени сервера и порта.

Шесть из одного, полдюжины других, настройте файл apache httpd.conf, и вы скоро увидите ожидаемые результаты.

Ответ 2

Хорошо, думаю, я понял это. Мой администратор сервера изменил conf.d/ssl.conf на

SSLEngine On
# and other SSL directives

<VirtualHost *:443>
        ServerName my.example.com
        ServerAlias my

        # and more directives
</VirtualHost>

to

<VirtualHost IP_ADDRESS:443>
        ServerName my.example.com
        ServerAlias my

        SSLEngine On
        # and other SSL directives

        # and more directives
</VirtualHost>

и теперь PHP видит правильный SERVER_PORT # (443) и $_SERVER ['HTTPS']. Таким образом, либо он помещал директивы SSL в директиву VirtualHost для my.example.com, либо, может быть, он изменял директиву VirtualHost для ссылки на фактический IP-адрес, а не на wild card, который разрешил эту проблему. Спасибо всем за вашу помощь в этом.

Ответ 3

Кажется, я помню, как это случилось со мной, когда я обновил свой Apache пару лет назад. Это оказалось плохой SSLCipherSuite, IIRC. В основном убедитесь, что у вас есть полная конфигурация SSL:

У вас есть ваши шифры, сертификаты и ключ? И SSLEngine On? Что-то вроде этого требуется в вашей конфигурации минимально...

SSLEngine on

SSLCipherSuite ALL:! ADH:! EXPORT56: RC4 + RSA: + HIGH: + MEDIUM: + LOW: + SSLv2: + EXP: + eNULL SSLCertificateFile/path/to/apache/conf/server.crt SSLCertificateKeyFile/path/to/apache/conf/server.key

... и если вы хотите проверить сертификаты клиента, вам также потребуется что-то вроде:

Требование SSLVerifyClient SSLVerifyDepth 10 SSLCACertificateFile/path/to/apache/conf/trustedpubkeys.crt

Удачи!

Если вы хотите проверить, что это действительно происходит, запустите сниффер, например, tcpdump или wirehark. Для tcpdump я бы использовал командную строку, например...

tcpdump -i eth0 -nn -s 1600 ip proto 17 и host IP_ADDRESS

(где IP_ADDRESS - это квадрат fqdn или dotted вашего сервера)

Затем получите страницу с дампом $_SERVER var или страницу phpinfo() и т.д.

Ваш дамп $_SERVER var показывает ваш удаленный порт, чтобы вы могли видеть, какое из ваших соединений использовало этот порт, и было ли оно подключено к порту 80 или 443.

Wireshark позволит вам делать то же самое, если вы больше похожи на GUI.