基于libcurl与OpenSSL实现硬编码SSL证书白名单遇阻求助
问题分析与解决方案
你的问题核心是:代码仅将硬编码证书追加到信任存储,而非替换原有信任体系。即使清空了CAINFO和CAPATH,OpenSSL的SSL上下文仍可能保留默认信任的证书,导致任何合法CA签发的证书都能通过验证,最终出现"无论插什么证书都能连接"的情况。
方案1:公钥固定(推荐,更简洁可靠)
libcurl提供CURLOPT_PINNEDPUBLICKEY选项,直接硬编码服务器公钥的哈希值,仅匹配对应公钥的服务器,彻底阻断MITM攻击。
步骤:
- 提取服务器公钥的SHA256哈希:
openssl s_client -connect your-server.com:443 < /dev/null | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 - 将哈希值硬编码到代码中:
int main(void) { // ... 初始化curl等操作 ... // 替换为你的服务器公钥SHA256哈希 const char* pinned_pubkey = "sha256/abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"; curl_easy_setopt(ch, CURLOPT_PINNEDPUBLICKEY, pinned_pubkey); curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, 1L); // ... 执行请求 ... }
这种方法无需处理证书链,只要服务器公钥不变就持续有效,比硬编码证书更易维护。
方案2:严格只信任硬编码证书
如果坚持使用证书白名单,需修改sslctx_function,确保清空原有信任存储,仅添加目标证书:
修改后的回调函数:
static CURLcode sslctx_function(CURL *curl, void *sslctx, void *parm) { CURLcode rv = CURLE_ABORTED_BY_CALLBACK; static const char my_server_cert[] = "-----BEGIN CERTIFICATE-----\n" // 替换为你的服务器证书完整内容 "-----END CERTIFICATE-----\n"; SSL_CTX *ctx = (SSL_CTX *)sslctx; X509_STORE *cts = SSL_CTX_get_cert_store(ctx); if (!cts) return rv; // 清空原有信任存储,确保无残留默认CA X509_STORE_cleanup(cts); // 从内存加载证书 BIO *cbio = BIO_new_mem_buf(my_server_cert, sizeof(my_server_cert)-1); // 去掉字符串末尾的'\0' if (!cbio) return rv; X509 *cert = PEM_read_bio_X509(cbio, NULL, NULL, NULL); BIO_free(cbio); if (!cert) return rv; // 将证书添加到信任存储 if (X509_STORE_add_cert(cts, cert) != 1) { X509_free(cert); return rv; } X509_free(cert); // 设置验证规则:仅验证服务器证书本身,不接受链上其他CA SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); SSL_CTX_set_verify_depth(ctx, 1); rv = CURLE_OK; return rv; }
主函数配套设置:
int main(void) { // ... 初始化curl ... curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, 1L); // 禁用默认CA路径 curl_easy_setopt(ch, CURLOPT_CAINFO, NULL); curl_easy_setopt(ch, CURLOPT_CAPATH, NULL); // 设置自定义SSL上下文回调 curl_easy_setopt(ch, CURLOPT_SSL_CTX_FUNCTION, sslctx_function); // ... 执行请求 ... }
关键修改说明:
X509_STORE_cleanup(cts):清空原有信任存储,避免默认CA干扰- 直接加载单个服务器证书,设置验证深度为1,确保仅验证目标证书
- 简化证书加载逻辑,避免原代码中证书链解析的冗余操作
内容的提问来源于stack exchange,提问作者caprisonne
相关产品推荐
相关产品推荐

