首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 判斷 HTTPS 連線的正確姿勢:$_SERVER 變數深度解析

     編輯:PHP 相關知識

在 PHP 中判斷目前請求是否為 HTTPS,看似簡單卻藏著許多陷阱。單純檢查 $_SERVER['HTTPS'] 在反向代理、負載平衡器、CDN 等架構下常失效。本文詳細說明各種環境下的正確判斷方法,並提供一個通用的輔助函數。

常見判斷方式與適用場景

方法 程式碼 適用環境 缺點
標準 HTTPS 變數 $_SERVER['HTTPS'] === 'on' Apache + mod_ssl 直連、Nginx + php-fpm 直連(正確設定 fastcgi_param HTTPS on) 反向代理/SSL 卸載後失效
端口號判斷 $_SERVER['SERVER_PORT'] === '443' 直連環境備用 非標準端口、代理環境失效
HTTP_X_FORWARDED_PROTO $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' AWS ELB、Cloudflare、Nginx 反向代理(已設定 proxy_set_header X-Forwarded-Proto $scheme) Header 可被偽造,需信任代理層
HTTP_FRONT_END_HTTPS $_SERVER['HTTP_FRONT_END_HTTPS'] === 'on' Microsoft Azure、IIS ARR 代理 特定平台專用
HTTP_X_FORWARDED_SSL $_SERVER['HTTP_X_FORWARDED_SSL'] === 'on' 部分舊版代理/負載平衡器 非標準、較少見

通用判斷函數(支援多層代理)

<?php
/**
 * 判斷目前請求是否為 HTTPS
 * 支援直連、單層/多層反向代理、CDN、雲端負載平衡器
 *
 * @param array $trustedProxies 信任的代理 IP 範圍 (CIDR),為空則信任所有 REMOTE_ADDR(不建議生產環境)
 * @return bool
 */
function isHttps(array $trustedProxies = []): bool
{
    // 1. 直接連線環境
    if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
        return true;
    }
    if (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] === '443') {
        return true;
    }

    // 2. 反向代理環境:檢查 X-Forwarded-Proto(標準)、其他常見 Header
    $forwardedProto = $_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '';
    if ($forwardedProto) {
        // 可能包含多個值:"https, https, http",取第一個(客戶端原始協定)
        $firstProto = trim(explode(',', $forwardedProto)[0]);
        if (strtolower($firstProto) === 'https') {
            return true;
        }
    }

    // 3. 其他代理 Header
    $proxyHeaders = [
        'HTTP_FRONT_END_HTTPS' => 'on',
        'HTTP_X_FORWARDED_SSL' => 'on',
        'HTTP_X_FORWARDED_PROTOCOL' => 'https',
        'HTTP_X_URL_SCHEME' => 'https',
    ];
    foreach ($proxyHeaders as $header => $expected) {
        if (isset($_SERVER[$header]) && strtolower($_SERVER[$header]) === $expected) {
            return true;
        }
    }

    return false;
}

// 使用範例
if (isHttps()) {
    echo '安全連線 (HTTPS)';
} else {
    echo '非加密連線 (HTTP)';
}

進階:信任代理 IP 白名單(防 Header 偽造)

若架構已知(如固定的 Nginx 代理 IP、AWS ELB IP 範圍),應驗證 REMOTE_ADDR 來自信任代理,才信任 X-Forwarded-* Header:

<?php
function isHttpsSecure(array $trustedProxyCidrs = []): bool
{
    $remoteAddr = $_SERVER['REMOTE_ADDR'] ?? '';

    // 若設定白名單,檢查來源 IP 是否在信任範圍內
    if ($trustedProxyCidrs) {
        $trusted = false;
        foreach ($trustedProxyCidrs as $cidr) {
            if (ipInCidr($remoteAddr, $cidr)) {
                $trusted = true;
                break;
            }
        }
        if (!$trusted) {
            // 來源非信任代理,僅信任直連 HTTPS 變數
            return (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on')
                || (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] === '443');
        }
    }

    // 信任代理或無白名單設定時,使用標準判斷邏輯
    return isHttps();
}

/** 簡易 CIDR 比對(IPv4) */
function ipInCidr(string $ip, string $cidr): bool
{
    [$subnet, $mask] = explode('/', $cidr);
    $mask = (int)$mask;
    $ipLong = ip2long($ip);
    $subnetLong = ip2long($subnet);
    $maskLong = -1 << (32 - $mask);
    return ($ipLong & $maskLong) === ($subnetLong & $maskLong);
}

// 使用範例:信任 10.0.0.0/8 (內網) 和 172.31.0.0/16 (AWS VPC)
$trusted = ['10.0.0.0/8', '172.31.0.0/16'];
var_dump(isHttpsSecure($trusted));

框架整合建議

  • Laravel:設定 App\Http\Middleware\TrustProxies 中介層,填入信任代理 IP,框架自動處理 Request::secure()。
  • Symfony:設定 framework.trusted_proxies 與 framework.trusted_headers。
  • CodeIgniter 4:Config\App::$proxyIPs 設定信任代理。
  • 原生 PHP:在入口檔案最早處引入上述 isHttpsSecure() 並定義為常數 define('IS_HTTPS', isHttpsSecure([...]));。

常見錯誤與除錯技巧

  1. 重複輸出問題:原文程式碼重複兩次 if/else 區塊,請移除重複。
  2. Header 大小寫:$_SERVER Key 為大寫且加前綴 HTTP_(如 HTTP_X_FORWARDED_PROTO),勿直接用 X-Forwarded-Proto。
  3. Nginx 設定缺失:確認 proxy_set_header X-Forwarded-Proto $scheme; 已加入 location 區塊。
  4. Cloudflare:啟用「Always Use HTTPS」後,來源協定為 HTTPS,但若未開啟「Automatic HTTPS Rewrites」,可能仍需檢查 CF-Visitor Header。

結語

判斷 HTTPS 的關鍵在於理解流量進入路徑:直連看 HTTPS/SERVER_PORT,經代理看 X-Forwarded-Proto。生產環境務必配合信任代理 IP 白名單,防止 Header 偽造導致安全判斷繞過。將判斷邏輯封裝為可複用函數並整合至框架請求生命週期,才能確保全站一致性與安全性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved