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)