如何在libcurl中正确配置SSL选项以连接Firebase实时数据库并解决Schannel报错
libcurl连接Firebase实时数据库时TLS握手校验报错问题
现有代码实现
响应数据写入回调函数
static size_t my_write(void* buffer, size_t size, size_t nmemb, void* param) { std::string& text = *static_cast<std::string*>(param); size_t totalsize = size * nmemb; text.append(static_cast<char*>(buffer), totalsize); return totalsize; }
主函数核心流程
int main() { std::string result; CURL* curl; CURLcode res; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (curl) { curl_easy_setopt(curl, CURLOPT_URL, "https://example-project-62811-default-rtdb.firebaseio.com/.json"); curl_easy_setopt(curl, CURLOPT_PROXY_SSL_OPTIONS, CURLSSLOPT_ALLOW_BEAST | CURLSSLOPT_NO_REVOKE); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_write); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); res = curl_easy_perform(curl); curl_easy_cleanup(curl); if (CURLE_OK != res) { std::cerr << "CURL ERROR: " << res << "\n"; } } curl_global_cleanup(); std::cout << result << "\n\n"; }
故障现象
- 上述代码访问普通公开第三方测试API时可正常运行
- 访问Firebase实时数据库地址时,连接在TLS握手阶段失败,输出日志如下:
Trying 35.201.97.85:443... Connected to example-project-62811-default-rtdb.firebaseio.com (35.201.97.85) port 443 (#0) schannel: next InitializeSecurityContext failed: Unknown error (0x80092013) Closing connection 0 schannel: shutting down SSL/TLS connection with example-project-62811-default-rtdb.firebaseio.com port 443 CURL ERROR: 35
已开展的排查操作
- 命令行直接执行curl访问同一地址,可完全复现相同报错
- 命令行添加
--ssl-no-revoke参数后,curl可正常拉取Firebase返回的数据,对应执行命令为:curl https://example-project-62811-default-rtdb.firebaseio.com/.json --ssl-no-revoke - 参照命令行参数的对应关系,在代码中设置了
CURLOPT_PROXY_SSL_OPTIONS配置,携带CURLSSLOPT_NO_REVOKE标记,但配置未生效,依然报相同错误
问题根因
- 代码中误用了libcurl配置项:
CURLOPT_PROXY_SSL_OPTIONS的作用是配置libcurl与HTTPS代理服务器建立SSL连接时的行为,在未设置代理的场景下,这个配置完全不会影响libcurl和目标业务服务器(此处即Firebase)的直连TLS握手流程 - Windows平台下,命令行
--ssl-no-revoke参数对应的libcurl C API配置项是CURLOPT_SSL_OPTIONS,不是带PROXY前缀的版本 - 报错码
0x80092013对应Windows Schannel组件的证书吊销校验失败错误,本质是当前网络环境下无法正常连通证书吊销列表服务器,Schannel默认会拦截该类连接,设置CURLSSLOPT_NO_REVOKE标记即可跳过该校验逻辑
正确修改方案
将原有错误的代理SSL配置行,替换为作用于目标服务器直连的SSL配置项即可:
// 原错误写法:仅作用于代理连接的SSL配置,无代理时不生效 // curl_easy_setopt(curl, CURLOPT_PROXY_SSL_OPTIONS, CURLSSLOPT_ALLOW_BEAST | CURLSSLOPT_NO_REVOKE); // 正确写法:作用于与目标服务器直连的SSL配置,和命令行参数效果对齐 curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_ALLOW_BEAST | CURLSSLOPT_NO_REVOKE);
补充说明:两个SSL配置项的作用域完全独立
CURLOPT_SSL_OPTIONS:控制libcurl和目标业务主机建立TLS连接时的行为CURLOPT_PROXY_SSL_OPTIONS:仅控制libcurl和代理服务器建立TLS连接时的行为,无代理场景下不会参与目标主机的连接流程
内容的提问来源于stack exchange,提问作者batuhansenoglu
相关产品推荐
相关产品推荐

