PHP使用负载均衡器时识别客户端请求协议(HTTPS、HTTP)

反向代理(负载平衡器)可以使用HTTP与Web服务器通信,即使对反向代理本身的请求是HTTPS(来自客户端)。在这种情况下,负载平衡器可以添加额外的头,如X-Forwarded-Proto(这是事实上的标准)。其他一些非标准的变体是。

X-Forwarded-Protocol: https
X-Forwarded-Ssl: on 
X-Url-Scheme: https

# Microsoft applications and load-balancers:
Front-End-Https: on

要通过$_SERVER超全局访问这些属性,请记住,例如要访问X-Forwarded-Protocol,你将使用$_SERVER['HTTP_X_FORWARDED_PROTO'],等等。

根据我们使用的负载平衡器,我们可以添加对这些头信息的检查作为后备措施。例如,AWS ELB、HAProxy和Nginx Proxy,都使用X-Forwarded-Proto。因此,如果我们使用其中之一,我们可以添加一个后备检查,像这样。

$isHttps =
    (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on')
    || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
;

虽然,X-Forwarded-Proto是事实上的标准,但RFC-7239现在定义了Forwarded-*,旨在取代X-Forwarded-*头。然而,X-前缀惯例是非常广为人知和使用的,RFC-7239标准可能需要一段时间才能被广泛采用。

使用REQUEST_SCHEME环境变量

大多数Web服务器默认没有设置$_SERVER['REQUEST_SCHEME'],因此,它可能不是很可靠。而且,在官方的php文档中还没有提到它。然而,它可以在较新版本的流行网络服务器中使用,如Apache 2.4+Nginx 1.9.2+。所以,如果你正在使用这些服务器,或者希望支持现代/流行的网络服务器,那么在其中添加一个检查可能是有意义的。例如,考虑一下。

$isHttps = 
    (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on')
    || (isset($_SERVER['REQUEST_SCHEME']) && $_SERVER['REQUEST_SCHEME'] === 'https')
    || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
;

涵盖大多数情况的复制/粘贴解决方案

$isHttps = 
    $_SERVER['HTTPS']
    ?? $_SERVER['REQUEST_SCHEME']
    ?? $_SERVER['HTTP_X_FORWARDED_PROTO']
    ?? null
;

$isHttps = 
    $isHttps && (
        strcasecmp('on', $isHttps) == 0
        || strcasecmp('https', $isHttps) == 0
    )
;

这对大多数情况来说应该是足够的。尽管如此,如果你认为覆盖的检查还不够,你可以增加一个额外的支持来检查端口。

注意strcasecmp()的使用,对字符串进行不区分大小写的匹配。这可能很重要,因为对HTTPS协议环境变量的大小写没有硬性规定。

参考:PHP使用负载均衡器时识别客户端请求协议(HTTPS、HTTP)

posted @ 2022-05-10 21:25  MkDocsMan  阅读(358)  评论(0编辑  收藏  举报