security - 在 WinINet 中手动验证服务器证书

标签 security ssl wininet

我正在尝试对 WinINet 客户端实现手动自签名 SSL 证书验证。我尝试通过使用 INTERNET_OPTION_SECURITY_CERTIFICATE 或 INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT 参数调用 InternetQueryOption 来处理它,但两者都返回服务器证书的一些内部解释,都不允许访问原始证书公钥或至少是指纹。

我该如何验证证书?...

最佳答案

除了之前的答案。 如果您想手动检查不受信任的根证书(例如自签名),您需要

  1. 设置标志以忽略不受信任的证书
// Open request before
HINTERNET hRequest = HttpOpenRequest(hConnect, _T("POST"), action, NULL, NULL, NULL, dwFlags, 0);
if (!hRequest) return GetLastError();

// set ignore options to request
DWORD dwFlags;
DWORD dwBuffLen = sizeof(dwFlags);
InternetQueryOption(hRequest, INTERNET_OPTION_SECURITY_FLAGS, (LPVOID)&dwFlags, &dwBuffLen);
dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
InternetSetOption (hRequest, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags));
  • 发送数据请求
  • if (HttpSendRequest(hRequest, strHeaders, strHeaders.GetLength(), data, len)) {
    
  • 只有在数据请求返回后,我们才能查看证书信息并检查指纹。 要获取指纹,我们必须使用 cryptapi 中的方法, 所以需要#include“WinCrypt.h”并将crypt32.lib添加到链接器
  • PCCERT_CHAIN_CONTEXT CertCtx=NULL;
    DWORD cbCertSize = sizeof(&CertCtx);
    
    // Get certificate chain information
    if (InternetQueryOption(hRequest, INTERNET_OPTION_SERVER_CERT_CHAIN_CONTEXT, (LPVOID)&CertCtx, &cbCertSize))
    {
        PCCERT_CHAIN_CONTEXT pChainContext=CertCtx;
    
        CERT_SIMPLE_CHAIN *simpleCertificateChainWithinContext = NULL;
        for (int i=0; i<pChainContext->cChain; i++)
        {
            simpleCertificateChainWithinContext=pChainContext->rgpChain[i];
            
            // We can check any certificates from chain, but if selfsigned it will be single
            for (int simpleCertChainIndex = 0; simpleCertChainIndex < simpleCertificateChainWithinContext->cElement; simpleCertChainIndex++)
            {
                // get the CertContext from the array
                PCCERT_CONTEXT pCertContext = simpleCertificateChainWithinContext->rgpElement[simpleCertChainIndex]->pCertContext;
                
                // Public key can be getted from
                //  (((*((*pCertContext).pCertInfo)).SubjectPublicKeyInfo).PublicKey).pbData
                // but better to use thumbprint to check
    
                // CERT_HASH_PROP_ID - is a thumbprint
                BYTE thumbprint[1024];
                DWORD len = 1024;
                if (CertGetCertificateContextProperty(pCertContext, CERT_HASH_PROP_ID, thumbprint, &len)) {
                    //
                    // !!! HERE WE CAN CHECK THUMPRINT WITH TRUSTED(PREVIOUSLY SAVED)
                    // and return error, or accept request output.
                    //
                }
            }
        }
        
        // important! Free the CertCtx
        CertFreeCertificateChain(CertCtx);
    }
    
  • 为什么使用指纹来比较证书? 证书中有三个有趣的字段需要比较: 序列号、公钥、指纹。 序列号只是颁发证书的 CA 选择的唯一编号, 公钥很好的解决方案,但指纹是通过完整证书计算的哈希值 (https://security.stackexchange.com/questions/35691/what-is-the-difference-between-serial-number-and-thumbprint)
  • 关于security - 在 WinINet 中手动验证服务器证书,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/732107/

    相关文章:

    google-chrome - JMeter https 代理记录不工作

    caching - 以编程方式清除 WinInet DNS 缓存

    multithreading - 从互联网下载文件,同时能够随时中止下载

    java - Java Web Start 是否需要启用 Java 浏览器插件?

    Facebook 应用程序未在 Chrome 中显示不安全的内容消息

    wpf - Microsoft 脚本控制 - 阻止脚本访问系统?

    security - Kafka SSL 安全设置导致问题

    C++ WinInet 和回调不工作

    security - 如果提供程序和 RP 在同一个域中,在 iframe 中加载 OpenID 提供程序是不是一个坏主意?

    java - Google 如何验证 API 调用中的 SHA1 和程序包名称?