web-dev-qa-db-fra.com

TLS 1.2 non négocié dans .NET 4.7 sans appel explicite de ServicePointManager.SecurityProtocol

Je dois mettre à niveau une application .NET pour prendre en charge l'appel d'une API sur un site Web uniquement compatible avec TLS 1.2. D'après ce que j'ai lu, si l'application cible 4.6 ou plus, elle utilisera TLS 1.2 par défaut.

Pour tester, j'ai créé une application Windows Forms qui cible 4.7. Malheureusement, il y a une erreur lorsque je ne définis pas explicitement ServicePointManager.SecurityProtocol. Voici le code:

HttpClient _client = new HttpClient();

var msg = new StringBuilder();

// If I uncomment the next line it works, but fails even with 4.7
// ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

var httpWebRequest = (HttpWebRequest)WebRequest.Create("https://sandbox.authorize.net");

httpWebRequest.KeepAlive = false;

try
{
    var httpWebResponse = (HttpWebResponse) httpWebRequest.GetResponse();

    msg.AppendLine("The HTTP request Headers for the first request are: ");

    foreach (var header in httpWebRequest.Headers)
    {
        msg.AppendLine(header.ToString());
    }

    ResponseTextBox.Text = msg.ToString();

}
catch (Exception exception)
{
   ResponseTextBox.Text = exception.Message;

   if (exception.InnerException != null)
   {
       ResponseTextBox.Text += Environment.NewLine + @"  ->" + exception.InnerException.Message;

       if (exception.InnerException.InnerException != null)
       {
            ResponseTextBox.Text += Environment.NewLine + @"     ->" + exception.InnerException.InnerException.Message;
       }
   }
}

Si vous décommentez la ligne suivante:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

ça marche. Ce n'est pas une bonne solution, car elle code la version de TLS à utiliser, elle n'utilisera donc pas TLS 1.3 à l'avenir.

Que dois-je faire d'autre pour que cela fonctionne sans avoir cette ligne. Je teste depuis une machine Windows 10 avec la version 4.7 installée.

Mise à jour

J'ai essayé un test avec HttpClient et eu les mêmes résultats, je devais définir explicitement SecurityProtocol.

Code:

var msg = new StringBuilder();

// Need to uncomment code below for TLS 1.2 to be used
// ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

try
{
   var response = await _client.GetAsync(@"https://sandbox.authorize.net");

   msg.AppendLine("response.IsSuccessStatusCode : " + response.IsSuccessStatusCode);

   msg.AppendLine(await response.Content.ReadAsStringAsync());

   textBox.Text = msg.ToString();
  }

  catch (Exception exception)
  {
      textBox.Text = exception.Message;

      if (exception.InnerException != null)
      {
          textBox.Text += Environment.NewLine + @"  ->" + exception.InnerException.Message;
      }
   }
26
Josh

J'ai trouvé une solution. Cela ne répond pas à la question de savoir pourquoi TLS 1.2 n'est pas utilisé par défaut sous Win10 avec .NET 4.7, mais cela me permet de ne pas avoir à définir ServicePointManager.SecurityProtocol.

La solution qui a fonctionné à partir de mes applications de test 4.5.2 et 4.7 consiste à ajouter ce qui suit à app.config:

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

Voici l'intégralité de app.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7"/>
    </startup>
    <runtime>
      <AppContextSwitchOverrides value="Switch.System.Net.DontEnableSchUseStrongCrypto=false"/>
    </runtime>
</configuration>
6
Josh

À partir des applications qui ciblent le .NET Framework 4.7, la valeur par défaut de la propriété ServicePointManager.SecurityProtocol est SecurityProtocolType. SystemDefault .

Cette modification permet aux API de réseau .NET Framework basées sur SslStream (telles que FTP, HTTPS et SMTP) d'hériter des protocoles de sécurité par défaut du système d'exploitation d'utiliser des valeurs codées en dur définies par le .NET Framework.

C'est la raison du nouveau comportement que vous avez rencontré et le besoin de la nouvelle configuration:

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

Voir ici et ici

14

En guise d'alternative à la réponse de Nick Y, j'ai découvert que, sous Windows 7 avec .NET 4.7+, je devais activer ces paramètres de registre pour que le package Microsoft Secure Channel (Schannel) envoie correctement TLS1.1 et TLS1.2.

Cela permet au client .NET de continuer à avoir System.Net.ServicePointManager.SecurityProtocol réglé sur SystemDefault et obtenez TLS 1.1 et 1.2 sur un ordinateur Windows 7.

L'utilisation de l'option SystemDefault permet à .NET de différer la sélection des protocoles sur le système d'exploitation. Cela signifie que lorsque Microsoft publie des correctifs sur le système d'exploitation pour désactiver les protocoles non sécurisés ou active la prise en charge de nouveaux protocoles dans leur bibliothèque SCHANNEL native, les applications du framework .NET en cours d'exécution obtiennent automatiquement ce nouveau comportement.

Voici les entrées de registre:

[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.2\Client]
"DisabledByDefault"=dword:00000000
7
MerickOWA

Je suis sous Windows 7 et .NET 4.7.1

La recommandation d'utiliser Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols et Switch.System.Net.DontEnableSchUseStrongCrypto mentionné dans deux autres réponses ne fonctionnait pas dans mon projet et le code d'OP échouait aussi.

Vérification du code source pour ServicePointManager et LocalAppContextSwitches Je suis tombé sur un autre paramètre de configuration qui a fonctionné.

<runtime>
  <AppContextSwitchOverrides value="Switch.System.Net.DontEnableSystemDefaultTlsVersions=true" />
</runtime>
5
Nick Y

J'ai eu le même problème (Windows 10 et SSL3/TLS uniquement ... pas par défaut du système) avec une application héritée ciblant 4.7.2. Mon problème était qu'au cours du processus de mise à niveau au fil des ans, nous n'avons jamais ajouté l'élément targetFramework à l'élément system.web> httpRuntime (Remarque: il existait bien sur system.web> compilation élément). Avant de prendre des mesures plus importantes, assurez-vous que votre site system.web ressemble à ce qui suit:

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

Dans l'exemple ci-dessus, permutez 4.7.2 pour la version de l'infrastructure utilisée, à savoir> = 4.7.

4
scottheckel