我有一个特定的应用程序,需要使用客户端证书进行HTTPS请求的相互身份验证。服务器具有灵活的证书验证策略,允许它接受服务器证书存储中不存在的自签名客户端证书。众所周知,使用curl作为客户端可以正常工作。
我通过测试和数据包嗅探确定的是,Microsoft的ASP.NET HttpClient
在SSL握手期间试图过于聪明。如果该客户端证书与服务器的可信根之一具有信任链,则该特定客户端将仅使用客户端证书(来自WebRequestHandler.ClientCertificates
集合)。我观察到的是,如果没有带有信任链的证书,那么客户端在握手期间根本不会发送证书。
这是可以理解的默认行为,但过于严格,似乎没有办法将其关闭。我已经尝试了各种其他WebRequestHandler
属性,包括AuthenticationLevel
和ClientCertificateOptions
,但无济于事。
有没有办法强制HttpClient
在ClientCertificates
集合中可用时发送客户端证书,即使它似乎不会在服务器端验证?我对简单和肮脏(反射黑客)解决方案持开放态度,因为我真的需要这个客户端才能工作。
答案 0 :(得分:0)
我有同样的问题,也没有运气。当WebRequesthandler有时确实根据线程/ AppPool凭据发送证书时,还观察到一种奇怪的行为。
我设法通过用RestClient替换HttpClient来解决此问题。 RestClient是OpenSource,可通过nuget获得。
API非常相似,并且在不抱怨证书的情况下进行所需的魔术操作:
var restClient = new RestClient($"{serviceBaseUrl}{requestUrl}");
X509Certificate certificate = GetCertificateFromSomewhere();
restClient.ClientCertificates = new X509CertificateCollection { certificate };
var request = new RestRequest(Method.POST);
request.RequestFormat = DataFormat.Json;
request.AddParameter(new Parameter()
{
Type = ParameterType.RequestBody,
Name = "Body",
ContentType = "application/json",
Value = "{your_json_body}"
});
IRestResponse<T> response = client.Execute<T>(request);
if (response.ErrorException != null)
{
throw new Exception(response.Content, response.ErrorException);
}
return response.Data;
答案 1 :(得分:0)
我认为您有多个证书,或者需要多个证书,并且需要附加它们。 您可以向X509CertificateCollection添加尽可能多的证书。 其中之一必须与https服务器证书匹配,否则您将无法调用Web服务。
try
{
X509Certificate2 clientCert = GetClientCertificate("cert1");
X509Certificate2 clientCert = GetClientCertificate("cert2");
X509Certificate2 clientCert = GetClientCertificate("cert3");
WebRequestHandler requestHandler = new WebRequestHandler();
requestHandler.ClientCertificates.Add(clientCert1);
requestHandler.ClientCertificates.Add(clientCert2);
requestHandler.ClientCertificates.Add(clientCert3); HttpClient客户端=新的HttpClient(requestHandler) { BaseAddress =新的Uri(“ http://localhost:3020/”) };
HttpResponseMessage response = client.GetAsync("customers").Result;
response.EnsureSuccessStatusCode();
string responseContent = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(responseContent);
}
catch (Exception ex)
{
Console.WriteLine("Exception while executing the test code: {0}", ex.Message);
}
然后调用此请求。
private static X509Certificate2 GetClientCertificate( string probablerightcert)
{
X509Store userCaStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
try
{
userCaStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certificatesInStore = userCaStore.Certificates;
X509Certificate2Collection findResult = certificatesInStore.Find(X509FindType.FindBySubjectName, probablerightcert, true);
X509Certificate2 clientCertificate = null;
if (findResult.Count == 1)
{
clientCertificate = findResult[0];
}
else
{
throw new Exception("Unable to locate the correct client certificate.");
}
return clientCertificate;
}
catch
{
throw;
}
finally
{
userCaStore.Close();
}
}