- 解决使用代理后 Git 无法获取本地证书问题。
#解决使用代理后 Git 无法获取本地证书问题
问题背景
- 使用代理访问 Github 后,出现
SSL certificate problem: unable to get local issuer certificate
的错误。
- 使用代理访问 Github 后,出现
原理解析
- Git 配置的 http.sslBackend 默认使用 Openssl 会默认使用自己证书的信任链,如果代理的证书没有被客户端 Git 自带的证书库信任就会出现这个问题,使用 schannel 可以避免非透明代理出现这个的问题。
- Git 配置的 http.sslBackend 默认使用 Openssl 会默认使用自己证书的信任链,如果代理的证书没有被客户端 Git 自带的证书库信任就会出现这个问题,使用 schannel 可以避免非透明代理出现这个的问题。
解决方法
- 配置 Git 跳过 SSL 验证(不推荐)
- 配置 Git 在使用代理时使用正确的证书链
- 让 Git 使用 Windows 系统的证书存储来验证 SSL 连接
#问题背景
- 在使用steamcommunity 302代理访问 Github 后,出现
SSL certificate problem: unable to get local issuer certificate
的错误,而且无法使用HTTPS上传项目到 Github 仓库了。
#原理解析
Git 使用 HTTPS 时验证 SSL 证书的基本流程
建立 TCP 连接:
- Git 客户端首先通过网络建立与远程服务器的 TCP 连接。
- Git 客户端首先通过网络建立与远程服务器的 TCP 连接。
SSL/TLS 握手:
- 客户端和服务器进行 SSL/TLS 握手,交换加密信息。
- 客户端和服务器进行 SSL/TLS 握手,交换加密信息。
服务器证书验证:
- 服务器在握手过程中提供自己的 SSL 证书,Git 客户端需要验证这个证书是否是由受信任的证书颁发机构(CA)签发的,是否有效(未过期),以及是否与远程服务器的域名匹配。
- 服务器在握手过程中提供自己的 SSL 证书,Git 客户端需要验证这个证书是否是由受信任的证书颁发机构(CA)签发的,是否有效(未过期),以及是否与远程服务器的域名匹配。
建立加密连接:
- 验证通过后,双方使用共享的加密密钥进行加密通信,确保数据的安全性。
- 验证通过后,双方使用共享的加密密钥进行加密通信,确保数据的安全性。
调试 SSL 证书问题
- 使用 GIT_CURL_VERBOSE 环境变量调试 Git 和服务器之间的 SSL/TLS 握手,能输出详细的 SSL 证书信息。
GIT_CURL_VERBOSE=1 git clone https://github.com/username/repo.git
通过上图使用代理前后 SSL 证书信息可以看出:
- 服务器返回被 CA 签名过的证书给客户端后
- 客户端验证该证书的然后强行中断了 TLS 连接
- 然后客户端通过 TCP 连接发送 TLS 协议中的警告通知,告知对方无法识别证书的颁发机构(CA)
总结:也就是说问题在 TLS 证书传给客户端处出现验证失败。
- 使用 GIT_CURL_VERBOSE 环境变量调试 Git 和服务器之间的 SSL/TLS 握手,能输出详细的 SSL 证书信息。
梳理该过程的证书链验证流程
正常情况下证书链(或者使用透明代理 -> 代理正常转发证书链不会影响客户端和Github证书验证)
- GitHub 的服务器证书:这是 GitHub 服务器返回的原始证书,颁发给 github.com。
- GitHub 的中间证书:由受信任的 CA 机构签发,通常是 GitHub 使用的中间证书。
- CA 的根证书:根证书由一个公认的受信任的 CA(如 DigiCert、Let’s Encrypt 等)签发。
使用代理后的证书链(非透明代理 -> 常见的是使用 HTTPS 代理)
- 代理服务器的伪造证书:证书颁发给 github.com,但由代理服务器的中间证书签发。
- 代理的中间证书:代理会附带由自己信任的中间证书,目的是为了使客户端能够验证伪造的证书。
- 代理的根证书:如果代理是使用自签名的证书或由自己的私有 CA 颁发证书链,客户端必须信任这个根证书,否则会出现证书验证失败的错误。
总结: 也就是说非透明代理修改了 Github 和客户端之间的 TLS 建立过程。
解决思路
配置 Git 跳过 SSL 验证(不推荐)
配置 Git 在使用代理时使用正确的证书链
让 Git 使用 Windows 系统的证书存储来验证 SSL 连接
- Git 配置 http.sslBackend 使用 Schannel[1] (Windows SSL/TLS 栈)
客户端和代理建立连接时,会使用 Windows 操作系统的证书存储来验证 Github 服务器证书,不需要代理生成任何伪造的证书。
也就是说会直接使用 Windows 系统中已安装的证书(包括根证书和中间证书)来验证服务器证书。如果代理的证书是由一个已知的受信 CA 签发的,客户端(Windows)会信任它。
- Git 配置 http.sslBackend 使用 Schannel[1] (Windows SSL/TLS 栈)
#解决方法
配置 Git 跳过 SSL 验证(不推荐)
- 暂时禁用 SSL 验证(不推荐长期使用)
git config --global http.sslVerify false
- 暂时禁用 SSL 验证(不推荐长期使用)
配置 Git 在使用代理时使用正确的证书链
- 这里由于代理相关信息不清楚,就暂时不考虑
- 确保代理配置正确,再考虑添加代理证书链
git config --global http.sslCAinfo /path/to/proxy/certificate.pem
- 确保代理配置正确,再考虑添加代理证书链
- 这里由于代理相关信息不清楚,就暂时不考虑
让 Git 使用 Windows 系统的证书存储来验证 SSL 连接
- http.sslBackend: 这个配置项控制 Git 使用哪种 SSL/TLS 库来进行 HTTPS 连接的证书验证。
相关补充
Git 测试 HTTPS 连接
git ls-remote https://github.com/username/repo.git
Git 测试 SSH 连接
ssh -T [email protected]
Git 测试详细的 SSL 证书信息
GIT_CURL_VERBOSE=1 git clone https://github.com/username/repo.git
设置 Git 使用 HTTP/HTTPS 代理:
- git config --global http.proxy http://<代理地址>:<代理端口>
- git config --global https.proxy http://<代理地址>:<代理端口>
查看 OpenSSL 使用的证书存储位置(默认是Git安装目录下/mingw64/ssl)
openssl version -d