如何使用InternetSetOption设置SECURITY_FLAG_IGNORE_UNKNOWN_CA忽略自签名证书
问题分析与修复方案
你的代码存在几个关键问题,导致无法正确忽略自签名证书的未知CA错误:
1. InternetSetOption使用错误的选项标识符
你调用InternetSetOption时传入了INTERNET_OPTION_SECURITY_FLAGS,但要配置每连接的安全选项,必须使用INTERNET_OPTION_PER_CONNECTION_OPTION。
2. 安全标志设置不完整
INTERNET_PER_CONN_FLAGS对应的Value.dwValue需要包含基础连接标志(比如PROXY_TYPE_DIRECT,表示直接连接不使用代理),再叠加你需要的安全忽略标志,仅设置SECURITY_FLAG_IGNORE_UNKNOWN_CA无法生效。
3. 编码不匹配
HttpOpenRequest中使用了_T("HTTP/1.1")宽字符常量,但其他参数都是ANSI格式的char*,会导致编码冲突,需统一使用ANSI版本(去掉_T前缀)。
4. 错误检查缺失
代码未检查hSession和hConnect的创建结果,若这些句柄创建失败,后续操作都会无效。
修复后的完整代码
#include <windows.h> #include <wininet.h> #include <stdio.h> #define MAX_LEN 1024 int request(char * host, int port, char * endpoint, char * data, size_t dlen ) { LPCSTR accept[] = {"*/*", NULL}; char hdrs[] = "Content-Type: application/json"; HINTERNET hConnect = NULL, hSession = NULL, hRequest = NULL; // 创建Internet会话句柄并检查结果 hSession = InternetOpenA("", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (!hSession) { printf("InternetOpen失败,错误码: %ld\n", GetLastError()); goto cleanup; } // 配置每连接安全选项 INTERNET_PER_CONN_OPTION_LIST list; INTERNET_PER_CONN_OPTION ops[1]; DWORD dwBufSize = sizeof(list); ZeroMemory(&list, sizeof(list)); ZeroMemory(ops, sizeof(ops)); list.dwSize = sizeof(list); list.pszConnection = NULL; // 选项应用于所有连接 list.dwOptionCount = 1; list.pOptions = ops; ops[0].dwOption = INTERNET_PER_CONN_FLAGS; // 设置直接连接 + 忽略未知CA证书错误 ops[0].Value.dwValue = PROXY_TYPE_DIRECT | SECURITY_FLAG_IGNORE_UNKNOWN_CA; // 为会话设置每连接选项(也可单独为hRequest设置) if (!InternetSetOptionA(hSession, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize)) { printf("InternetSetOption失败,错误码: %ld\n", GetLastError()); goto cleanup; } // 创建连接句柄并检查结果 hConnect = InternetConnectA(hSession, host, port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1); if (!hConnect) { printf("InternetConnect失败,错误码: %ld\n", GetLastError()); goto cleanup; } // 创建HTTP请求句柄,统一使用ANSI版本,添加必要的安全忽略标志 hRequest = HttpOpenRequestA(hConnect, "GET", endpoint, "HTTP/1.1", NULL, accept, INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID, 1); if (!hRequest) { printf("HttpOpenRequest失败,错误码: %ld\n", GetLastError()); goto cleanup; } // 发送请求并读取响应 if (HttpSendRequestA(hRequest, hdrs, strlen(hdrs), data, dlen)) { DWORD received; char tmp[MAX_LEN]; ZeroMemory(tmp, MAX_LEN); while (InternetReadFile(hRequest, tmp, MAX_LEN - 1, &received) && received) { tmp[received] = '\0'; // 确保字符串终止 printf("%s", tmp); ZeroMemory(tmp, MAX_LEN); } } else { printf("HttpSendRequest失败,错误码: %ld\n", GetLastError()); } cleanup: // 按逆序释放句柄,避免资源泄漏 if (hRequest) InternetCloseHandle(hRequest); if (hConnect) InternetCloseHandle(hConnect); if (hSession) InternetCloseHandle(hSession); return 0; }
额外说明
- 所有WinINet函数均使用ANSI版本(后缀
A),彻底避免编码混淆;若需宽字符版本,可统一替换为W后缀。 - 添加了句柄安全释放逻辑,防止资源泄漏。
- 除
SECURITY_FLAG_IGNORE_UNKNOWN_CA外,在HttpOpenRequest中额外添加了INTERNET_FLAG_IGNORE_CERT_DATE_INVALID,可避免自签名证书过期导致的错误(不需要可直接移除)。 - 选项可设置在
hSession(全局生效)或hRequest(仅当前请求生效),可根据需求选择。
内容的提问来源于stack exchange,提问作者loaded_dypper
相关产品推荐
相关产品推荐

