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

PHP cURL 訪問 HTTPS 完整指南:從跳過驗證到嚴格 CA 憑證驗證

     編輯:PHP 相關知識

前言:三年前的坑與今天的理解

早期常見寫法直接關閉 SSL 驗證(CURLOPT_SSL_VERIFYPEER = false),雖能通訊但等同「裸奔」,中間人攻擊風險極高。本文系統梳理 HTTPS 請求的三種驗證層級與正確姿勢。

基礎封裝:支援 HTTP/HTTPS 自動切換

function curlPost(string $url, array $data = [], int $timeout = 30, bool $strictSSL = true): string
{
    $cacert = __DIR__ . '/cacert.pem'; // CA 根憑證路徑
    $isSSL  = strncmp($url, 'https://', 8) === 0;

    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL            => $url,
        CURLOPT_TIMEOUT        => $timeout,
        CURLOPT_CONNECTTIMEOUT => $timeout - 2,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $data,
        CURLOPT_HTTPHEADER     => ['Expect:'], // 避免 100-continue 導致大資料傳輸卡頓
    ]);

    if ($isSSL) {
        if ($strictSSL) {
            // 嚴格模式:僅信任 CA 簽發、驗證域名匹配
            curl_setopt_array($ch, [
                CURLOPT_SSL_VERIFYPEER => true,
                CURLOPT_CAINFO         => $cacert,
                CURLOPT_SSL_VERIFYHOST => 2, // 檢查 CN/SAN 與主機名匹配
            ]);
        } else {
            // 寬鬆模式:信任任何憑證,僅檢查是否有域名欄位
            curl_setopt_array($ch, [
                CURLOPT_SSL_VERIFYPEER => false,
                CURLOPT_SSL_VERIFYHOST => 1,
            ]);
        }
    }

    $ret = curl_exec($ch);
    // 失敗時可用 curl_error($ch) 診斷
    curl_close($ch);
    return $ret;
}

三種 SSL 驗證層級深度解析

層級CURLOPT_SSL_VERIFYPEERCURLOPT_SSL_VERIFYHOSTCURLOPT_CAINFO適用場景
嚴格(推薦生產) true 2 CA 根憑證路徑 目標站使用正規 CA 簽發憑證(DigiCert、Let's Encrypt、GlobalSign 等)
中等(僅驗證域名) false 1 不需要 自簽憑證、內網測試環境、開發階段臨時繞過
完全關閉(極不推薦) false 0 不需要 極少數舊系統相容,**生產環境嚴禁**

關鍵知識點補充

什麼是 CA 根憑證?

瀏覽器內建主流 CA 公鑰清單。cacert.pem 即打包這些公鑰的 PEM 檔,可從 cURL 官網 下載最新版,定期更新。

Common Name (CN) 與 SAN

憑證中的「主體替代名稱」擴展包含合法域名。VERIFYHOST=2 會同時檢查 CN 與 SAN 是否匹配請求主機名。

自簽憑證如何正確使用?

  1. 將自簽 CA 的公鑰加入專案專用 cacert-custom.pem。
  2. 代碼中指定 CURLOPT_CAINFO => __DIR__.'/cacert-custom.pem'。
  3. 如此仍保持 VERIFYPEER=true,安全性不打折。

常見錯誤排查

  • SSL certificate problem: self signed certificate → 未提供對應 CA 或憑證確為自簽。
  • SSL: certificate subject name does not match target host name → 域名不匹配(可能訪問 IP 而非域名、或憑證綁定錯誤)。
  • CURLOPT_CAINFO path not found → 路徑錯誤,建議用 __DIR__ 絕對路徑。

進階:支援 Client Certificate(雙向 TLS)

curl_setopt_array($ch, [
    CURLOPT_SSLCERT      => __DIR__ . '/client.pem',   // 客戶端憑證+私鑰
    CURLOPT_SSLCERTTYPE  => 'PEM',
    CURLOPT_SSLKEY       => __DIR__ . '/client.key',   // 若私鑰分離
    CURLOPT_SSLKEYTYPE   => 'PEM',
    CURLOPT_SSLKEYPASSWD => 'keypassword',             // 私鑰密碼(如有)
]);

總結

  1. 預設嚴格驗證,僅在受控環境臨時降級並加註 TODO。
  2. 專案內置 cacert.pem 並定期更新(Composer composer/ca-bundle 可自動維護)。
  3. 錯誤時輸出 curl_error($ch) 與 curl_getinfo($ch) 快速定位。
  4. 理解 HTTPS 本質:加密傳輸 + 身份驗證,缺一不可。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved