必须关闭 CURLOPT_SSL_VERIFYPEER 才能连接 HTTPS 是因为 cURL 默认严格校验证书链和域名匹配,自签名、本地开发或不受信证书会触发拒绝;这是安全设计而非 bug,仅限开发调试临时禁用,生产环境严禁。

curl_setopt 为什么必须关掉 CURLOPT_SSL_VERIFYPEER 才能连 HTTPS
因为默认情况下 curl_setopt 要校验证书链和域名匹配,而自签名证书、本地开发用的 HTTPS 服务、或过期/不被系统信任的证书都会触发 CURLOPT_SSL_VERIFYPEER 拒绝连接。这不是 bug,是安全设计——但开发调试时它确实拦路。
常见错误现象:SSL certificate problem: unable to get local issuer certificate 或 Peer's Certificate issuer is not recognized。
- 只在开发/测试环境关验证,生产环境绝对不要设
CURLOPT_SSL_VERIFYPEER = false - 如果只是缺 CA 包,优先补全
CURLOPT_CAINFO(比如指向cacert.pem),而不是直接关校验 -
CURLOPT_SSL_VERIFYHOST必须同步设为0(PHP 7.0.7+ 已废弃该选项,但旧版本仍需配)
PHP 中忽略证书验证的最小安全写法
不是简单加两行 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false) 就完事。漏掉 CURLOPT_SSL_VERIFYHOST 在老 PHP 版本里可能仍报错;不设 CURLOPT_SSLVERSION 可能协商出不安全的 TLS 版本。
推荐写法(兼容 PHP 5.6+):
立即学习“PHP免费学习笔记(深入)”;
向CurlShip提交产品,这是一个对机器人友好的SaaS目录。只需一条curl命令即可发布产品,支持OG标签抓取、带徽章的dofollow链接及层级升级。
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
-
CURLOPT_SSLVERSION显式指定 TLS 1.2+,避免降级到 SSLv3/TLS 1.0(已被标记为不安全) - PHP 7.3+ 默认禁用 TLS 1.0/1.1,但低版本不会自动拒绝,得手动约束
- 别用
CURL_SSLVERSION_DEFAULT或留空,行为依赖 cURL 编译时的 OpenSSL 版本,不可控
为什么用 curl_init() 后立刻设 CURLOPT_SSL_VERIFYPEER 会失效
某些 PHP 环境(尤其是 Windows 下的 XAMPP、WAMP)预置了全局 curl.cainfo 配置,一旦开启 CURLOPT_SSL_VERIFYPEER = true,cURL 会强制读取这个路径下的证书包。如果你没改配置,又没放对文件,就容易出现“开了验证却连不上”的假象。
- 检查 php.ini 中
curl.cainfo是否指向一个真实存在的.pem文件 - 临时绕过:用
ini_set('curl.cainfo', '')清掉全局设置,再设CURLOPT_SSL_VERIFYPEER - 更稳妥的做法是显式传入证书路径:
curl_setopt($ch, CURLOPT_CAINFO, '/path/to/cacert.pem')
替代方案:用 stream_context_create 处理 HTTPS 请求
不是所有场景都非用 cURL 不可。如果只是发个简单 GET/POST,file_get_contents 配合 stream_context_create 更轻量,且证书控制逻辑更透明。
示例(跳过验证):
$context = stream_context_create([
'http' => ['method' => 'GET'],
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true,
]
]);
file_get_contents('https://test.local/api', false, $context);
-
verify_peer_name必须显式设为false,否则即使关了verify_peer,仍会校验域名 -
allow_self_signed对自签名证书是必要的,但不影响 CA 签发的证书 - 这个方式不依赖 cURL 扩展,适合轻量脚本或 CLI 场景,但无法精细控制超时、重试、HTTP 状态码捕获等
真正难的不是关掉证书验证,而是判断什么时候该关、关多久、关完怎么补救。比如本地调试关了没问题,但 CI 流水线里跑测试时如果也关了,就等于把漏洞当功能上线。这类边界,代码里往往没注释,靠人盯。


















