客户端和服务器无法通信,因为它们没有通用的算法-ASP.NET C # IIS TLS 1.0/1.1/1.2-Win32Exception

我对 C # 支付追踪网关有意见。下面的代码一直运行良好,直到昨天我相信他们关闭了 SSL3由于贵宾犬利用。在运行下面的代码时,我们得到了以下消息。远程服务器已强制关闭连接。在对该问题进行了一些研究之后,我们确定,由于 IIS Server 7.5被配置为仍然使用 SSL3,因此 C # 默认为 SSL3,PayTrace 将强制关闭该连接。然后,我们从服务器上删除 SSL3。然后导致以下错误:

客户端和服务器无法通信,因为它们没有通用算法

我猜测,既然 SSL3已被删除,我们需要在服务器上安装另外的 SSL 算法。我们的 IT 人员声称 TLS 1.1和 TLS 1.2正在工作,ASP.NET 现在应该默认使用它们。但是我觉得我们还需要在服务器上安装一些其他的东西,我对 SSL 算法一无所知,所以我不知道从哪里开始。

var postUrl = new StringBuilder();


//Initialize url with configuration and parameter values...
postUrl.AppendFormat("UN~{0}|", this.MerchantLoginID);
postUrl.AppendFormat("PSWD~{0}|", this.MerchantTransactionKey);
postUrl.Append("TERMS~Y|METHOD~ProcessTranx|TRANXTYPE~Sale|");
postUrl.AppendFormat("CC~{0}|", cardNumber);
postUrl.AppendFormat("EXPMNTH~{0}|", expirationMonth.PadLeft(2, '0'));
postUrl.AppendFormat("EXPYR~{0}|", expirationYear);
postUrl.AppendFormat("AMOUNT~{0}|", transactionAmount);
postUrl.AppendFormat("BADDRESS~{0}|", this.AddressLine1);
postUrl.AppendFormat("BADDRESS2~{0}|", this.AddressLine2);
postUrl.AppendFormat("BCITY~{0}|", this.City);
postUrl.AppendFormat("BSTATE~{0}|", this.State);
postUrl.AppendFormat("BZIP~{0}|", this.Zip);
postUrl.AppendFormat("SADDRESS~{0}|", this.AddressLine1);
postUrl.AppendFormat("SADDRESS2~{0}|", this.AddressLine2);
postUrl.AppendFormat("SCITY~{0}|", this.City);
postUrl.AppendFormat("SSTATE~{0}|", this.State);
postUrl.AppendFormat("SZIP~{0}|", this.Zip);
if (!String.IsNullOrEmpty(this.Country))
{
postUrl.AppendFormat("BCOUNTRY~{0}|", this.Country);
}
if (!String.IsNullOrEmpty(this.Description))
{
postUrl.AppendFormat("DESCRIPTION~{0}|", this.Description);
}
if (!String.IsNullOrEmpty(this.InvoiceNumber))
{
postUrl.AppendFormat("INVOICE~{0}|", this.InvoiceNumber);
}
if (this.IsTestMode)
{
postUrl.AppendFormat("TEST~Y|");
}


//postUrl.Append();


WebClient wClient = new WebClient();
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
String sRequest = "PARMLIST=" + Url.Encode(postUrl.ToString());
wClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
string sResponse = "";
sResponse = wClient.UploadString(PayTraceUrl, sRequest);

另外,仅供参考,这个问题也发生在我们连接到第一数据 E4网关时,所以它不仅仅是一个 PayTrace 的东西。我的猜测是,随着越来越多的网关关闭对 SSL3的访问,我们将继续遇到其他网关的问题,直到这个问题在服务器上得到解决。此外,我在网上找到了一些建议,有些建议是在发出出站请求之前正确地放置以下代码:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;

不幸的是,这也不起作用,同样的错误。这就是为什么我认为需要在 IIS7.5服务器上安装一些额外的东西。我只是不确定是什么。

287030 次浏览

This was resolved. It turns out our IT Staff was correct. Both TLS 1.1 and TLS 1.2 were installed on the server. However, the issue was that our sites are running as ASP.NET 4.0 and you have to have ASP.NET 4.5 to run TLS 1.1 or TLS 1.2. So, to resolve the issue, our IT Staff had to re-enable TLS 1.0 to allow a connection with PayTrace.

So in short, the error message, "the client and server cannot communicate, because they do not possess a common algorithm", was caused because there was no SSL Protocol available on the server to communicate with PayTrace's servers.

UPDATE: Please do not enable TLS 1.0 on your servers, this was a temporary fix and is not longer applicable since there are now better work-arounds that ensure strong security practices. Please see accepted answer for a solution.

Enabling TLS 1.0 solved our issues as well (after disabling SSL v3). (Server 2012 R2 with ASP.net 4.0 website processing against PPI pay services). This is the RegEdit script I used to set everything the way I wanted. We only disabled SSL v3 for the Client and not the server as doing that broke other things that we were not ready to deal with yet. After we upgrade the site to .Net 4.5.2 then we will disable TLS 1.0 again.

This script enables all protocols, Server and Client except for SSL v3 for the Client.

Be sure to backup your registry!

Windows Registry Editor Version 5.00


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client]
"Enabled"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server]
"Enabled"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client]
"Enabled"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client]
"DisabledByDefault"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server]
"Enabled"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server]
"DisabledByDefault"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client]
"Enabled"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client]
"DisabledByDefault"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server]
"Enabled"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server]
"DisabledByDefault"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client]
"Enabled"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client]
"DisabledByDefault"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server]
"Enabled"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server]
"DisabledByDefault"=dword:00000000

After messing with this for days, my final fix for our issues required two things;

1) We added this line of code to all of our .Net libraries that make out bound api calls to other vendors that had also disabled their SSL v3.

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls; // (.Net 4 and below)

2) This is the final and FULL registry changes you will need when you are running ASP.Net 4.0 sites and will need to be slightly changed after you upgrade to ASP.Net 4.5.

After we rebooted the servers - all problems went away after this.

Windows Registry Editor Version 5.00


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client]
"DisabledByDefault"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client]
"Enabled"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server]
"DisabledByDefault"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server]
"Enabled"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client]
"DisabledByDefault"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client]
"Enabled"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server]
"DisabledByDefault"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server]
"Enabled"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client]
"Enabled"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client]
"DisabledByDefault"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server]
"Enabled"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server]
"DisabledByDefault"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client]
"Enabled"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client]
"DisabledByDefault"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server]
"Enabled"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server]
"DisabledByDefault"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client]
"Enabled"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client]
"DisabledByDefault"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server]
"Enabled"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server]
"DisabledByDefault"=dword:00000000

There are several other posts about this now and they all point to enabling TLS 1.2. Anything less is unsafe.

You can do this in .NET 3.5 with a patch.
You can do this in .NET 4.0 and 4.5 with a single line of code

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; // .NET 4.5
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; // .NET 4.0

In .NET 4.6, it automatically uses TLS 1.2.

See here for more details: .NET support for TLS.

In a previous answer, it was suggested to use this line of code for .Net 4.5:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; // .NET 4.5

I would encourage you to OR that value in to whatever the existing values are like this:

ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12; // .NET 4.5

If you look at the list of values, you notice that they are a power of two. This way, in the future when things shift to TLS 2.0 for example, your code will still work.

In previous answers a few registry keys that might not exist are missed. They are SchUseStrongCrypto that must exist to allow to TLS protocols work properly.

After the registry keys have been imported to registry it should not be required to make changes in code like

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;

Below there are all registry keys and values that are needed for x64 windows OS. If you have 32bit OS (x86) just remove the last 2 lines. TLS 1.0 will be disabled by the registry script. Restarting OS is required.

Windows Registry Editor Version 5.00


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols]


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0]


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client]
"DisabledByDefault"=dword:00000001
"enabled"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\server]
"disabledbydefault"=dword:00000001
"enabled"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\ssl 3.0]


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\ssl 3.0\client]
"disabledbydefault"=dword:00000001
"enabled"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\ssl 3.0\server]
"disabledbydefault"=dword:00000001
"enabled"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\tls 1.0]


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\tls 1.0\client]
"disabledbydefault"=dword:00000001
"enabled"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\tls 1.0\server]
"disabledbydefault"=dword:00000001
"enabled"=dword:00000000


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\tls 1.1]


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\tls 1.1\client]
"disabledbydefault"=dword:00000000
"enabled"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\tls 1.1\server]
"disabledbydefault"=dword:00000000
"enabled"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\tls 1.2]


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\tls 1.2\client]
"disabledbydefault"=dword:00000000
"enabled"=dword:00000001


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\tls 1.2\server]
"disabledbydefault"=dword:00000000
"enabled"=dword:00000001


[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319]
"SchUseStrongCrypto"=dword:00000001


[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319]
"SchUseStrongCrypto"=dword:00000001

In my case, even though Target Framework of Project was 4.7.1, I was still getting same Error, Solution was to change httpRuntime in web.config under system.web to 4.7.1!

I fixed this error by upgrading the app from .Net Framework 4.5 to 4.6.2.

TLS-1.2 was correctly installed on the server, and older versions like TLS-1.1 were disabled. However, .Net 4.5 does not support TLS-1.2.

My app is running in .net 4.7.2. Simplest solution was to add this to the config:

  <system.web>
<httpRuntime targetFramework="4.7.2"/>
</system.web>

There are two possible scenario, in my case I used 2nd point.

  1. If you are facing this issue in production environment and you can easily deploy new code to the production then you can use of below solution.

    You can add below line of code before making api call,

    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; // .NET 4.5

  2. If you cannot deploy new code and you want to resolve with the same code which is present in the production, then this issue can be done by changing some configuration setting file. You can add either of one in your config file.

<runtime>
<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSchUseStrongCrypto=false"/>
</runtime>

or

<runtime>
<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSystemDefaultTlsVersions=false"/>
</runtime>

There are a couple of things that you need to check related to this.

Whenever there is an error like this thrown related to making a secure connection, try running a script like the one below in Powershell with the name of the machine or the uri (like "www.google.com") to get results back for each of the different protocol types:

 function Test-SocketSslProtocols {
    

[CmdletBinding()]
param(
[Parameter(Mandatory=$true)][string]$ComputerName,
[int]$Port = 443,
[string[]]$ProtocolNames = $null
)


#set results list
$ProtocolStatusObjArr = [System.Collections.ArrayList]@()




if($ProtocolNames -eq $null){


#if parameter $ProtocolNames empty get system list
$ProtocolNames = [System.Security.Authentication.SslProtocols] | Get-Member -Static -MemberType Property | Where-Object { $_.Name -notin @("Default", "None") } | ForEach-Object { $_.Name }


}
 

foreach($ProtocolName in $ProtocolNames){


#create and connect socket
#use default port 443 unless defined otherwise
#if the port specified is not listening it will throw in error
#ensure listening port is a tls exposed port
$Socket = New-Object System.Net.Sockets.Socket([System.Net.Sockets.SocketType]::Stream, [System.Net.Sockets.ProtocolType]::Tcp)
$Socket.Connect($ComputerName, $Port)


#initialize default obj
$ProtocolStatusObj = [PSCustomObject]@{
Computer = $ComputerName
Port = $Port
ProtocolName = $ProtocolName
IsActive = $false
KeySize = $null
SignatureAlgorithm = $null
Certificate = $null
}


try {


#create netstream
$NetStream = New-Object System.Net.Sockets.NetworkStream($Socket, $true)


#wrap stream in security sslstream
$SslStream = New-Object System.Net.Security.SslStream($NetStream, $true)
$SslStream.AuthenticateAsClient($ComputerName, $null, $ProtocolName, $false)
         

$RemoteCertificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$SslStream.RemoteCertificate
$ProtocolStatusObj.IsActive = $true
$ProtocolStatusObj.KeySize = $RemoteCertificate.PublicKey.Key.KeySize
$ProtocolStatusObj.SignatureAlgorithm = $RemoteCertificate.SignatureAlgorithm.FriendlyName
$ProtocolStatusObj.Certificate = $RemoteCertificate


}
catch  {


$ProtocolStatusObj.IsActive = $false
Write-Error "Failure to connect to machine $ComputerName using protocol: $ProtocolName."
Write-Error $_


}
finally {
            

$SslStream.Close()
        

}


[void]$ProtocolStatusObjArr.Add($ProtocolStatusObj)


}


Write-Output $ProtocolStatusObjArr


}


Test-SocketSslProtocols -ComputerName "www.google.com"

It will try to establish socket connections and return complete objects for each attempt and successful connection.

After seeing what returns, check your computer registry via regedit (put "regedit" in run or look up "Registry Editor"), place

Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL

in the filepath and ensure that you have the appropriate TLS Protocol enabled for whatever server you're trying to connect to (from the results you had returned from the scripts). Adjust as necessary and then reset your computer (this is required). Try connecting with the powershell script again and see what results you get back. If still unsuccessful, ensure that the algorithms, hashes, and ciphers that need to be enabled are narrowing down what needs to be enabled (IISCrypto is a good application for this and is available for free. It will give you a real time view of what is enabled or disabled in your SChannel registry where all these things are located).

Also keep in mind the Windows version, DotNet version, and updates you have currently installed because despite a lot of TLS options being enabled by default in Windows 10, previous versions required patches to enable the option.

One last thing: TLS is a TWO-WAY street (keep this in mind) with the idea being that the server's having things available is just as important as the client. If the server only offers to connect via TLS 1.2 using certain algorithms then no client will be able to connect with anything else. Also, if the client won't connect with anything else other than a certain protocol or ciphersuite the connection won't work. Browsers are also something that need to be taken into account with this because of their forcing errors on HTTP2 for anything done with less than TLS 1.2 DESPITE there NOT actually being an error (they throw it to try and get people to upgrade but the registry settings do exist to modify this behavior).

In my case I solved the problem by enabling the last TLS version in the .Net Framework as explained in this article:

https://learn.microsoft.com/dotnet/framework/network-programming/tls

set these registry keys:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319] "SystemDefaultTlsVersions"=dword:00000001
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319] "SystemDefaultTlsVersions"=dword:00000001
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319] "SchUseStrongCrypto"=dword:00000001
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319] " SchUseStrongCrypto"=dword:00000001

I had the same error when connecting from Windows Server 2012. I resolved by changing the TLS and SSL settings using the IIS Crypto executable. Specifically, I disabled Server Protocols SSL 3.0 and TLS 1.0. I also disabled Client Protocol SSL 3.0 (I believe this is what did the trick). I used a server that was working correctly as the basis for determining the ideal settings. Screenshot - IIS Crypto Settings