同localhost环境跨域名调用API出现SSL证书验证失败如何解决
自签证书同服务器双站点OAuth请求SSL校验失败排查指南
已排除的非根因场景
通过现有现象可以直接排除以下方向,避免无效排查:
- PHP OpenSSL全局环境异常:外网公开HTTPS端点请求正常,说明基础加密组件工作正常
- Web服务SSL配置异常:浏览器可正常访问两个域名的HTTPS服务,说明站点证书的域名匹配、端口监听、证书文件加载都无问题
- 业务代码逻辑异常:此前Docker独立部署环境下跨域调用正常,说明CI3、CI4的OAuth业务流程本身无bug
- PHP OAuth扩展实现逻辑无关:用原生cURL直接请求domain_b接口也报完全相同的证书校验错误,说明问题是SSL链路配置不匹配,和扩展的业务封装无关
核心问题定位
从报错栈可以看出,所有错误都发生在PHP底层流的SSL握手环节,和两个常见的配置失效点直接相关:
- OAuth扩展的
disableSSLChecks()方法作用范围有限:该方法仅对扩展内部封装的cURL请求逻辑生效,当getRequestToken()走PHP原生流包装器发起请求时,关闭SSL校验的配置不会传递到底层流的SSL上下文,导致校验逻辑仍然执行,这就是为什么方法调用了但没生效的原因。 - RHEL8的OpenSSL校验策略较严格:默认配置下会强制校验服务端证书的颁发者合法性、主机名匹配性,自签证书如果没有被加入客户端的信任CA列表,就会直接抛出
certificate verify failed错误。此前Docker环境下请求正常,本质是容器内的OpenSSL默认校验策略更宽松,CA加载路径和当前宿主机不一致。
分步排查与解决操作
- 先验证domain_b服务端的证书链完整性
执行命令直接和domain_b的443端口做SSL握手,定位具体校验失败的节点:
查看输出末尾的openssl s_client -connect domain_b.tld:443 -servername domain_b.tld -CAfile /path/to/签发domain_b服务端证书的根CA.crtVerify return code:- 如果返回
20、19类错误,说明CA文件路径不对,或者权限不足导致PHP进程无法读取 - 如果返回
0 (ok),说明CA文件本身正确,只是PHP的请求链路没有加载到这个CA
- 如果返回
- 修复OAuth扩展配置不生效的问题
不要仅依赖$conn->disableSSLChecks()方法,在发起OAuth请求前,直接给PHP全局流设置默认SSL上下文,绕过扩展的配置传递bug:
这个配置直接作用于PHP所有原生流请求的SSL层,不会因为扩展的实现缺陷导致配置失效。// 开发环境临时使用,生产环境不建议关闭校验 stream_context_set_default([ 'ssl' => [ 'verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true ] ]); - 修正CA配置之前不生效的问题
此前用setCAPath()配置失败,通常是三个原因:- 传入的是domain_b的站点证书文件,而不是签发该站点证书的根CA文件
- 证书文件的所有者/权限不对,php-fpm运行用户(apache/nginx)没有读权限,导致PHP无法加载CA
- 配置路径的时候没有把CA加入系统信任库,导致OpenSSL找不到对应的证书
可通过以下操作验证配置正确性: - 将domain_b的根CA文件复制到RHEL8的CA信任目录,执行更新命令:
cp /path/to/domain_b根CA.crt /etc/pki/ca-trust/source/anchors/ update-ca-trust extract - 直接执行
curl https://domain_b.tld,如果不带-k参数能正常返回响应,说明CA配置正确,此时再发起OAuth请求就不会出现校验失败的问题
- 区分两类证书的校验逻辑,避免配置混淆
当前报错是校验domain_b的服务端SSL证书失败,和两个站点各自独立的用户认证客户端CA体系完全无关,不需要把用户证书的CA加入对方的信任列表,只要信任对方的服务端根CA即可,避免冗余配置引入新的双向认证报错。
适配生产环境的兼容方案
开发环境打通请求后,按照生产环境的安全策略调整配置:
- 不要在生产环境长期关闭SSL校验,而是通过将domain_b的服务端根CA加入domain_a所在服务的信任CA列表,实现严格证书校验的同时,保证跨域请求正常
- 验证SELinux状态是否影响php-fpm读取CA证书文件:即使SELinux处于Permissive模式,也可以通过
ls -Z命令查看CA文件的安全上下文是否和php-fpm进程的允许访问类型匹配,避免无日志的权限拦截。
内容的提问来源于stack exchange,提问作者ZombieShellback
相关产品推荐
相关产品推荐

