我无法绕过生产服务器中的证书验证,因为从未调用过 ServicePointManager.ServerCertificateValidationCallback
:
ServicePointManager.ServerCertificateValidationCallback = ValidateRemoteCertificate;
...
private bool ValidateRemoteCertificate(
object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors policyErrors)
{
LogActionToTable(EntrySeverity.Information,
$"ValidateRemoteCertificate() Certificate name: {cert.Subject}");
return true;
}
从 Web 应用程序中的方法调用时,该行永远不会执行,奇怪足够从单元测试 (NUnit) 正确调用它。 p>
我确实在对远程 API 的任何其他调用之前添加了此调用。
我做错了什么?
如果我只是这样做,它甚至都不起作用:
ServicePointManager
.ServerCertificateValidationCallback +=
(sender, cert, chain, sslPolicyErrors) => true;
这一定很简单,但我已经用了好几天了,我无法让它正常工作。
无论我是在手动构建 XML 的地方使用 RestSharp 调用,还是通过 wsdl.exe
工具生成的代理进行调用,我总是从调用中得到这个:
The request was aborted: Could not create SSL/TLS secure channel.
并在日志文件中启用 Trace,我得到:
System.Net 信息:0:[7912] SecureChannel#14469269 - 证书的类型为 X509Certificate2 并包含私钥。
System.Net 信息:0:[7912] AcquireCredentialsHandle(包 = Microsoft 统一安全协议(protocol)提供程序,意图 = 出站,scc = System.Net.SecureCredential)
System.Net 信息:0:[7912] InitializeSecurityContext(凭证 = System.Net.SafeFreeCredential_SECURITY,上下文 =(空),targetName = onni.unicom.fi,inFlags = ReplayDetect,SequenceDetect, secret 性,AllocateMemory,InitManualCredValidation)
System.Net 信息:0:[7912] InitializeSecurityContext(缓冲区内长度=0,缓冲区外长度=170,返回代码=ContinueNeeded)。
System.Net 信息:0:[7912] InitializeSecurityContext(凭证 = System.Net.SafeFreeCredential_SECURITY,上下文 = 14899210:2119fd0,targetName = onni.unicom.fi,inFlags = ReplayDetect,SequenceDetect, secret 性,AllocateMemory,InitManualCredValidation)
System.Net 信息:0:[7912] InitializeSecurityContext(In-Buffers count=2,Out-Buffer length=0,返回代码=CredentialsNeeded)。
System.Net 信息:0:[7912] SecureChannel#14469269 - 我们有用户提供的证书。服务器已指定 1 个颁发者。寻找与任何颁发者相匹配的证书。
System.Net 信息:0:[7912] SecureChannel#14469269 - 剩下 0 个客户端证书可供选择。
System.Net 信息:0:[7912] 使用缓存的凭据句柄。
System.Net 信息:0:[7912] InitializeSecurityContext(凭证 = System.Net.SafeFreeCredential_SECURITY,上下文 = 14899210:2119fd0,targetName = onni.unicom.fi,inFlags = ReplayDetect,SequenceDetect, secret 性,AllocateMemory,InitManualCredValidation)
System.Net 信息:0:[7912] InitializeSecurityContext(缓冲区内计数=2,缓冲区外长度=173,返回代码=ContinueNeeded)。
System.Net 信息:0:[7912] InitializeSecurityContext(凭证 = System.Net.SafeFreeCredential_SECURITY,上下文 = 14899210:2119fd0,targetName = onni.unicom.fi,inFlags = ReplayDetect,SequenceDetect, secret 性,AllocateMemory,InitManualCredValidation)
System.Net 信息:0:[7912] InitializeSecurityContext(缓冲区内计数=2,缓冲区外长度=0,返回代码=CertUnknown)。
System.Net 错误:0:[7912] HttpWebRequest 中的异常#25731266::- 请求已中止:无法创建 SSL/TLS 安全通道。
System.Net 错误:0:[7912] HttpWebRequest 中的异常#25731266::EndGetRequestStream - 请求被中止:无法创建 SSL/TLS 安全通道。
最重要的:
System.Net Information: 0 : [7912] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=CertUnknown).
为什么 ServicePointManager.ServerCertificateValidationCallback
调用没有绕过它?
没有代理的代码:
private CardBalanceInfo ApiGetCardBalance(string cardNumber)
{
LogActionToTable(EntrySeverity.Information, $"ApiGetCardBalance('{cardNumber}')");
var soapEnvelope =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
" <soap:Header/>" +
" <soap:Body>" +
" <csi:getBalance xmlns:csi=\"urn:si.tm.webservice.uniassociation.unicom.com\">" +
" <csi:balanceId>" +
$" <entityName>{cardNumber}</entityName>" +
" </csi:balanceId>" +
" </csi:getBalance>" +
" </soap:Body>" +
"</soap:Envelope>";
const string soapUrl = "treasurymanagement/si";
const string soapAction = "http://www.unicom.fi/uAASTreasuryManagementSI/getBalance";
var response = MakeApiCall(soapUrl, soapAction, soapEnvelope);
return response.ToBalanceInfo();
}
代理代码:
private CardBalanceInfo ApiGetCardBalanceFromProxy(string cardNumber)
{
LogActionToTable(EntrySeverity.Information, $"ApiGetCardBalanceFromProxy('{cardNumber}')");
using (var service = new uAASTreasuryManagementSIService())
{
service.Timeout = 10000; // 10 sec
service.Url = _settings.BaseUrl.TrimEnd('/') + "/treasurymanagement/si";
service.ClientCertificates.Add(_clientCertificate);
var card = new getBalance()
{
balanceId = new EntityId
{
entityName = cardNumber
}
};
var balanceResponse = service.getBalance(card); // get API response
LogActionToTable(EntrySeverity.Information, $"ApiGetCardBalanceFromProxy success.");
return new CardBalanceInfo()
{
AvailableBalance = balanceResponse.balance.availableBalanceValue,
Balance = balanceResponse.balance.balanceValue,
BalanceId = balanceResponse.balance.balanceId.ToString()
};
}
}
最佳答案
我不认为证书验证是您的问题。
ServerCertificateValidationCallback在对证书进行自定义验证时使用。这在证书的主机名与您调用的服务的 URL 不匹配的开发或质量检查环境中最常需要。
您会知道何时遇到此问题,因为您会收到包含以下错误详细信息的 SecurityNeogtiationException:
其他信息:无法与权限“{HOSTNAME}”建立 SSL/TLS 安全通道的信任关系
这是我在本地计算机上关闭 ServerCertificateValidationCallback 时的样子。
我建议您将注意力转移到
The request was aborted: Could not create SSL/TLS secure channel.
因为这似乎是完全不同的问题。幸运的是,我还没有遇到 :-) 这里的答案将是一个很好的起点:The request was aborted: Could not create SSL/TLS secure channel
HTH
关于c# - 绕过证书验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37032525/