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

PHP cURL 訪問 HTTPS 完整指南:憑證驗證與常見坑點

     編輯:PHP 相關知識

核心概念:SSL 驗證三層防護

cURL 訪問 HTTPS 時,CURLOPT_SSL_VERIFYPEER 與 CURLOPT_SSL_VERIFYHOST 控制驗證嚴格度:

選項值行為
CURLOPT_SSL_VERIFYPEERtrue (預設)驗證伺服器憑證是否由信任 CA 簽發(需提供 CA 憑證包)
false信任任何憑證(含自簽、過期、偽造),極度不安全
CURLOPT_SSL_VERIFYHOST2 (預設)驗證憑證中的 Common Name (CN) 或 Subject Alternative Name (SAN) 是否匹配請求主機名
1僅檢查憑證中是否存在 CN(不比對主機名)
0完全不檢查主機名

通用 cURL POST 封裝函數

<?php
/**
 * cURL POST 請求(支援 HTTPS 雙向驗證)
 *
 * @param string $url      目標網址
 * @param array  $data     POST 欄位陣列
 * @param int    $timeout  逾時秒數
 * @param bool   $strict   HTTPS 是否嚴格驗證 CA
 * @return string|false 回應內容或 false
 */
function curlPost($url, $data = [], $timeout = 30, $strict = true) {
    $ch = curl_init();

    // 基礎設定
    curl_setopt_array($ch, [
        CURLOPT_URL            => $url,
        CURLOPT_TIMEOUT        => $timeout,
        CURLOPT_CONNECTTIMEOUT => max(1, $timeout - 2),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $data,
        CURLOPT_HTTPHEADER     => ['Expect:'], // 避免 100 Continue 導致大資料傳送延遲
        CURLOPT_SSL_VERIFYPEER => $strict,
        CURLOPT_SSL_VERIFYHOST => $strict ? 2 : 0,
    ]);

    // 嚴格模式需指定 CA 憑證包
    if ($strict) {
        $caCert = __DIR__ . '/cacert.pem'; // 建議放專案目錄,隨部署更新
        if (is_file($caCert)) {
            curl_setopt($ch, CURLOPT_CAINFO, $caCert);
        } else {
            // 回退:使用系統預設 CA 路徑
            curl_setopt($ch, CURLOPT_CAPATH, '/etc/ssl/certs');
        }
    }

    $response = curl_exec($ch);

    if ($response === false) {
        $error = curl_error($ch);
        curl_close($ch);
        error_log("cURL Error [$url]: $error");
        return false;
    }

    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    // 可選:非 2xx 視為失敗
    if ($httpCode < 200 || $httpCode >= 300) {
        error_log("HTTP $httpCode [$url]: " . substr($response, 0, 200));
        return false;
    }

    return $response;
}
?>

CA 憑證包獲取與維護

  • 官方來源: https://curl.se/ca/cacert.pem (Mozilla 信任清單轉換)
  • 部署建議: 專案佈建腳本自動下載最新版,或使用 Composer 套件 paragonie/certainty 自動同步。
  • 系統路徑: CentOS/RHEL: /etc/pki/tls/certs/ca-bundle.crt,Ubuntu/Debian: /etc/ssl/certs/ca-certificates.crt

常見場景與配置策略

1. 生產環境呼叫正規 API(嚴格模式)

$result = curlPost('https://api.payment.com/charge', $orderData, 30, true);

2. 開發/測試環境自簽憑證(寬鬆模式)

$result = curlPost('https://dev.internal/api', $data, 30, false);
// ⚠️ 僅限內網測試,嚴禁生產環境使用

3. 指定客戶端憑證(雙向 TLS / mTLS)

curl_setopt($ch, CURLOPT_SSLCERT, '/path/to/client.pem');
curl_setopt($ch, CURLOPT_SSLKEY,  '/path/to/client.key');
curl_setopt($ch, CURLOPT_SSLKEYPASSWD, 'keypassword'); // 若私鑰有密碼

效能優化技巧

  • 連線復用: 使用 curl_multi_* 或長連線池(如 Guzzle HttpClient)減少 TLS 握手開銷。
  • DNS 快取: 設定 CURLOPT_DNS_CACHE_TIMEOUT (預設 120 秒)。
  • 避免重複解析: 同域名多次請求時復用 $ch handle(需手動管理)。

除錯檢查清單

  1. curl_error($ch) 回傳什麼?(如 SSL certificate problem: self signed certificate)
  2. curl_getinfo($ch, CURLINFO_HTTP_CODE) 狀態碼?
  3. 目標伺服器憑證是否過期?(openssl s_client -connect host:443 -servername host < /dev/null)
  4. CA 憑證包是否最新?是否包含目標 CA?
  5. 主機名是否與憑證 CN/SAN 完全一致?(含 www 前綴)
  6. 防火牆/SELinux 是否阻擋出站 443?

總結

HTTPS 請求的安全性取決於「信任錨點」(CA 憑證包)與「身份驗證」(主機名比對)雙重把關。生產環境務必啟用嚴格驗證並定期更新 CA 憑證包;僅在隔離測試環境暫時關閉驗證。封裝通用函數統一管理參數,可大幅降低配置錯誤風險。

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