cURL 訪問 HTTPS 時,CURLOPT_SSL_VERIFYPEER 與 CURLOPT_SSL_VERIFYHOST 控制驗證嚴格度:
| 選項 | 值 | 行為 |
|---|---|---|
CURLOPT_SSL_VERIFYPEER | true (預設) | 驗證伺服器憑證是否由信任 CA 簽發(需提供 CA 憑證包) |
false | 信任任何憑證(含自簽、過期、偽造),極度不安全 | |
CURLOPT_SSL_VERIFYHOST | 2 (預設) | 驗證憑證中的 Common Name (CN) 或 Subject Alternative Name (SAN) 是否匹配請求主機名 |
1 | 僅檢查憑證中是否存在 CN(不比對主機名) | |
0 | 完全不檢查主機名 |
<?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;
}
?>
paragonie/certainty 自動同步。/etc/pki/tls/certs/ca-bundle.crt,Ubuntu/Debian: /etc/ssl/certs/ca-certificates.crt$result = curlPost('https://api.payment.com/charge', $orderData, 30, true);
$result = curlPost('https://dev.internal/api', $data, 30, false);
// ⚠️ 僅限內網測試,嚴禁生產環境使用
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 握手開銷。CURLOPT_DNS_CACHE_TIMEOUT (預設 120 秒)。$ch handle(需手動管理)。curl_error($ch) 回傳什麼?(如 SSL certificate problem: self signed certificate)curl_getinfo($ch, CURLINFO_HTTP_CODE) 狀態碼?openssl s_client -connect host:443 -servername host < /dev/null)HTTPS 請求的安全性取決於「信任錨點」(CA 憑證包)與「身份驗證」(主機名比對)雙重把關。生產環境務必啟用嚴格驗證並定期更新 CA 憑證包;僅在隔離測試環境暫時關閉驗證。封裝通用函數統一管理參數,可大幅降低配置錯誤風險。