我已经看过许多快速简便的 PHP测试,用于检查请求是HTTPS还是HTTP。
但是,大多数 失败 以这种方式或那种方式。例如IIS,Nginx,Apache,其他Web服务器,负载平衡器,支持反向代理。
我正在寻找在我的工作组中使用的最佳实践,可移植代码。
以下是我所拥有的(将PROTOCOL定义为'https://'或'http://')。
<!php
if ( !defined( 'PROTOCOL' ) ) {
if ( !empty( $_SERVER[ 'HTTPS' ] ) && $_SERVER[ 'HTTPS' ] !== 'off' ) {
// good in IIS and Apache
if ( 'on' == strtolower( $_SERVER[ 'HTTPS' ] ) ) define( 'PROTOCOL', 'https://' );
if ( '1' == $_SERVER[ 'HTTPS' ] ) define( 'PROTOCOL', 'https://' );
} elseif ( !empty( $_SERVER[ 'HTTP_FORWARDED' ] ) && false !== strpos( strtolower( $_SERVER[ 'HTTP_FORWARDED' ] ), 'https' ) ) {
// new standard RFC 7239 - reverse-proxies and load balancers.
// not widely implimented yet
define( 'PROTOCOL', 'https://' );
} elseif ( !empty( $_SERVER[ 'SERVER_PORT' ] ) && ( '443' == $_SERVER[ 'SERVER_PORT' ] ) ) {
// Is it port 443? Default Port for HTTPS
define( 'PROTOCOL', 'https://' );
} elseif ( !empty( $_SERVER[ 'HTTP_X_FORWARDED_SSL' ] ) && ( 'on' == strtolower( $_SERVER[ 'HTTP_X_FORWARDED_SSL' ] ) ) ) {
// reverse-proxies and load balancers - nginx.
define( 'PROTOCOL', 'https://' );
} elseif ( !empty( $_SERVER[ 'HTTP_X_FORWARDED_PROTO' ] ) && ( 'https' == strtolower( $_SERVER[ 'HTTP_X_FORWARDED_PROTO' ] ) ) ) {
// reverse-proxies and some load balancers.
define( 'PROTOCOL', 'https://' );
} elseif ( !empty( $_SERVER[ 'X_FORWARDED_PROTO' ] ) && ( 'https' == strtolower( $_SERVER[ 'X_FORWARDED_PROTO' ] ) ) ) {
// reverse-proxies and some load balancers.
define( 'PROTOCOL', 'https://' );
} else {
// default to http://
define( 'PROTOCOL', 'http://' );
}
}
我理解并接受一个人 可以(付出一些努力)使用没有SSL的端口443。尽管如此,端口443是默认的HTTPS端口。
对于讨论,这是WordPress使用的内容,但它有 许多失败 (负载均衡器,反向代理等)。
<!php
function is_ssl() {
if ( isset( $_SERVER['HTTPS'] ) ) {
if ( 'on' == strtolower( $_SERVER['HTTPS'] ) ) {
return true;
}
if ( '1' == $_SERVER['HTTPS'] ) {
return true;
}
} elseif ( isset($_SERVER['SERVER_PORT'] ) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
return true;
}
return false;
}
在官方WordPress Code Referance Page上,对于函数 is_ssl(),是这句话:
它不适用于某些负载均衡器背后的网站,尤其是网络解决方案托管网站。 ...有关详细信息,请阅读“WordPress is_ssl()在某些负载均衡器后面不起作用。”
支持HTTP_X_FORWARDED_PROTO的负载平衡器或反向代理背后的网站可以通过将以下代码添加到require_once调用上方的wp-config.php文件来修复:
<!php
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
$_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
$_SERVER['HTTPS'] = 'on';
本页未提及:
$_SERVER[ 'HTTP_X_FORWARDED_SSL' ]
或$_SERVER[ 'X_FORWARDED_PROTO' ]
但是,许多其他网页都提到了它们。
答案 0 :(得分:0)
从PHP的角度来看,正确的检查方法应该是检查$ _SERVER [&#39; HTTPS&#39;]是非空值而不是字符串"off"
。< / p>
if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
}
您的代码似乎要做的是要求此值为&#34; 1&#34;或&#34; on&#34;。但是,由于PHP手册暗示这可以是任何非空值(除了&#34; off&#34;),如果它是&#34; 1&#以外的非空值,则会失败34;或&#34; on&#34;。在实践中,这可能永远不会发生,但遵循规范只是为了确定是好的。
可以使用SERVER_PORT,但如果HTTPS没有,那么没有理由可行。此外,某些服务器配置错误可能允许在端口443上使用普通HTTP。
HTTP_X_FORWARDED_SSL和HTTP_X_FORWARDED_PROTO不可靠,因为任何客户都可以设置这些(即伪造它们)。
X_FORWARDED_PROTO可能是HTTP_X_FORWARDED_PROTO的替代品,可能存在同样的问题。
如果您正在执行上述操作但仍无法检测到它,那么错误位于PHP之外,您的服务器层根本就不会将HTTPS状态传递给您。否则,没有100%可靠的方法来检测它,而且大多数尝试都是讨厌的黑客攻击。
特别是,如果您的服务器以普通HTTP的形式接收它,但您有一个负载均衡器/转发代理在上游进行SSL终止,那么您无法可靠地检测是否通过HTTPS,因为该信息不可用于本地服务器。现在,在这里我会问你为什么要知道请求是否来自HTTPS,因为适当的解决方案取决于你使用这些信息的内容。最可靠的解决方案就是要求HTTPS,阻止所有普通的HTTP,此时您可以在应用程序中采用HTTPS。否则,也许上游代理设置了您可以读取的特定HTTP标头,但是您必须确保没有通过代理就没有流量可以直接到达本地服务器,并且代理会删除传入请求中的任何此类标头,以便他们不能伪造。
答案 1 :(得分:0)
下面是一个有点改进的wordpress功能。我添加了一个条件来检查HTTP_X_FORWARDED_PROTO标头值。因此,这将适用于托管在负载均衡器/反向代理之后的大多数网站。
/**
* Detect SSL status
* @return boolean
*/
function is_ssl() {
if ( isset($_SERVER['HTTPS']) ) {
if ( 'on' == strtolower($_SERVER['HTTPS']) )
return true;
if ( '1' == $_SERVER['HTTPS'] )
return true;
}
elseif ( isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
return true;
}
elseif(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' == $_SERVER['HTTP_X_FORWARDED_PROTO']){
return true;
}
return false;
}