$ _SERVER ['server_port']返回的端口号不正确

时间:2010-12-13 20:32:34

标签: php ssl

场景:我正在使用一些PHP在Apache Web服务器上工作。我将浏览器指向 https://my.example.com/test.php ,其中包含以下代码行:

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

为SERVER_PORT打印的值 80 ,而不是 443 。但是,如果我去 https://my.example.com:80/test.php Web服务器(Apache)barfs(连接到my.example.com:80时发生错误.SSL收到超过最大允许长度的记录。错误代码:ssl_error_rx_record_too_long)。如果我转到 https://my.example.com:443/test.php ,则网址重定向到 https://my.example.com/test.php ,没有任何错误或问题,但我的PHP打印出服务器端口为80而不是443。

以下是 conf.d / ssl.conf 文件中的相关部分(我删除了我认为无关的指令,并用IP_ADDRESS替换了实际的IP地址):

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] => admin@example.com
    [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文档,我认为如果通过HTTPS访问PHP脚本(我正在做的事情),它应该设置为非空值。

知道发生了什么事吗?我只是网络开发人员 - 我不管理这个服务器,但我的服务器管理员告诉我一切正常,但我想知道为什么$ _SERVER ['SERVER_PORT']在查看HTTPS URL时返回80而不是443。

编辑:我编辑了上面的示例来说明打印出整个$ _SERVER变量的结果。

编辑2 :按照以下评论中的建议尝试https://my.example.com:443/test.php做同样的事情 - SERVER_PORT为80且未设置HTTPS(特别是尝试将此网址重定向到{{3} })。

编辑3:好的,我发布了我认为是下面的答案(TL; DR:在VirtualHost指令中移动SSL指令并更改该指令以引用我的网站使用它的IP地址而不是通配符似乎已经解决了这个问题。)

3 个答案:

答案 0 :(得分:15)

我最近遇到了同样的问题,因为我遇到的一些代码掩盖了同样的问题,但这已经妨碍了。

我对问题的诊断如下: 这是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脚本正在做正确的事情,将_SERVER ['SERVER_PORT']报告为5150。

或者你的httpd.conf可以阅读

ServerName myservername.com
UseCanonicalName Off
Listen 5150

然后我挖掘了php(5.3.20)源代码和apache源代码,直到找到了行为的来源。

行为植根于(至少对于apached 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编号的形式时,案例代码将获取请求对象的ap_default_port(由apache人员将其默认设置为80)。

如果您需要将端口显式添加到httpd.conf中的ServerName指令,那么您的另一个选择是将UseCanonicalName设置为“Off”,这会强制server / core.c中的代码解析提取服务器名称和端口的URI请求。

其中六个,另外六个,调整你的apache httpd.conf文件,你很快就会看到预期的结果。

答案 1 :(得分:3)

好吧,我想我弄明白了。我的服务器管理员从

更改了 conf.d / ssl.conf
SSLEngine On
# and other SSL directives

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

        # and more directives
</VirtualHost>

<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指令放在my.example.com的VirtualHost指令中,要么就是更改VirtualHost指令以引用实际的IP地址而不是解决此问题的通配符。感谢大家的帮助。

答案 2 :(得分:2)

我似乎记得几年前我升级apache时发生这种情况。它最终成为一个糟糕的SSLCipherSuite,IIRC。基本上确保您有完整的SSL配置:

您是否定义了密码,证书和密钥?还有SSLEngine?最低限度的配置需要这样的东西......

SSLEngine

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或wireshark这样的嗅探器。对于tcpdump,我会使用命令行,如...

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

(其中IP_ADDRESS是服务器的fqdn或点四边形)

然后获取$ _SERVER var转储页面或phpinfo()页面等。

您的$ _SERVER var转储显示您的远程端口,因此您应该能够看到哪个连接使用了该端口,以及它是否已连接到端口80或443。

如果你更像是一个GUI用户,那么Wireshark会让你做同样的事情。