WebApi HttpClient不发送客户端证书

Tro*_*neh 25 .net c# ssl fiddler asp.net-web-api

我正在尝试使用客户端证书使用ssl和客户端身份验证来保护我的RESTful WebApi服务.

去测试; 我已生成一个自签名证书并放置在本地计算机,受信任的根证书颁发机构文件夹中,并且我已生成"服务器"和"客户端"证书.服务器的标准https无问题.

但是我在服务器中有一些代码来验证证书,当我使用提供客户端证书的测试客户端进行连接并且测试客户端返回403 Forbidden状态时,这永远不会被调用.

这实现了服务器在我的证书到达我的验证码之前失败了.但是,如果我启动提琴手它知道需要客户端证书并要求我提供一个到我的文档\ Fiddler2.我给了它我在我的测试客户端使用的相同客户端证书,我的服务器现在工作,并收到我期望的客户端证书!这意味着WebApi客户端没有正确发送证书,我的客户端代码与我找到的其他示例几乎相同.

    static async Task RunAsync()
    {
        try
        {
            var handler = new WebRequestHandler();
            handler.ClientCertificateOptions = ClientCertificateOption.Manual;
            handler.ClientCertificates.Add(GetClientCert());
            handler.ServerCertificateValidationCallback += Validate;
            handler.UseProxy = false;

            using (var client = new HttpClient(handler))
            {
                client.BaseAddress = new Uri("https://hostname:10001/");

                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));

                var response = await client.GetAsync("api/system/");
                var str = await response.Content.ReadAsStringAsync();

                Console.WriteLine(str);
            }
        } catch(Exception ex)
        {
            Console.Write(ex.Message);
        }
    }
Run Code Online (Sandbox Code Playgroud)

任何想法为什么它会在提琴手但不是我的测试客户端?

编辑:这是GetClientCert()的代码

private static X509Certificate GetClientCert()
    {            
        X509Store store = null;
        try
        {
            store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
            store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);

            var certs = store.Certificates.Find(X509FindType.FindBySubjectName, "Integration Client Certificate", true);

            if (certs.Count == 1)
            {
                var cert = certs[0];
                return cert;
            }
        }
        finally
        {
            if (store != null) 
                store.Close();
        }

        return null;
    }
Run Code Online (Sandbox Code Playgroud)

当然,测试代码不处理空证书,但我正在调试以确保找到正确的证书.

Spr*_*nky 3

有 2 种类型的证书。第一个是服务器所有者发送给您的公共 .cer 文件。这个文件只是一长串字符。第二个是密钥库证书,这是您创建的自签名证书,并将 cer 文件发送到您正在调用的服务器,然后他们安装它。根据您的安全程度,您可能需要将其中一项或两项添加到客户端(在您的情况下为处理程序)。我只看到在一台安全性非常安全的服务器上使用了密钥库证书。此代码从 bin/deployed 文件夹获取两个证书:

#region certificate Add
                // KeyStore is our self signed cert
                // TrustStore is cer file sent to you.

                // Get the path where the cert files are stored (this should handle running in debug mode in Visual Studio and deployed code) -- Not tested with deployed code
                string executableLocation = Path.GetDirectoryName(AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory);

                #region Add the TrustStore certificate

                // Get the cer file location
                string pfxLocation = executableLocation + "\\Certificates\\TheirCertificate.cer";

                // Add the certificate
                X509Certificate2 theirCert = new X509Certificate2();
                theirCert.Import(pfxLocation, "Password", X509KeyStorageFlags.DefaultKeySet);
                handler.ClientCertificates.Add(theirCert);
                #endregion

                #region Add the KeyStore 
                // Get the location
                pfxLocation = executableLocation + "\\Certificates\\YourCert.pfx";

                // Add the Certificate
                X509Certificate2 YourCert = new X509Certificate2();
                YourCert.Import(pfxLocation, "PASSWORD", X509KeyStorageFlags.DefaultKeySet);
                handler.ClientCertificates.Add(YourCert);
                #endregion

                #endregion
Run Code Online (Sandbox Code Playgroud)

另外 - 您需要处理证书错误(注意:这很糟糕 - 它表示所有证书问题都可以)您应该更改此代码以处理特定的证书问题,例如名称不匹配。这是我要做的事情。有很多关于如何执行此操作的示例。

此代码位于您的方法的顶部

// Ignore Certificate errors  need to fix to only handle 
ServicePointManager.ServerCertificateValidationCallback = MyCertHandler;
Run Code Online (Sandbox Code Playgroud)

类中某处的方法

private bool MyCertHandler(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors error)
    {
        // Ignore errors
        return true;
    }
Run Code Online (Sandbox Code Playgroud)