2017-06-25 2 views
4

Je dois mettre à niveau une application .NET pour prendre en charge un appel à une API sur un site Web qui ne prend en charge que 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.TLS 1.2 non négocié dans .NET 4.7 sans appel explicite ServicePointManager.SecurityProtocol

Pour tester j'ai créé une application Windows Forms qui cible 4.7. Malheureusement, il erreurs 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 supprimez la ligne suivante:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; 

cela fonctionne. Ce n'est pas une bonne solution car il code dur quelle version de TLS utiliser, donc il n'utilisera pas TLS 1.3 à l'avenir.

Quoi d'autre dois-je faire pour le faire fonctionner sans avoir cette ligne. Je teste à partir d'une machine Windows 10 avec 4.7 installé.

Mise à jour

J'ai essayé un test avec HttpClient et avait 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; 
     } 
    } 
+0

Vous pouvez OU les versions tls ensemble pour les soutenir tout si vous voulez. Mais pour éviter la nécessité de cette utilisation HttpClient (si vous pouvez faire votre code async sans aucun blocage des appels) – Crowcoder

+0

Je ne veux pas définir le protocole de sécurité, car quand un nouveau, tel que TLS 1.3 devient disponible, il ne serait pas être utilisé parce que ce n'est pas dans la liste. Je vais réécrire mon test avec HttpClient, existe-t-il une différence entre le protocole de sécurité par défaut utilisé par HttpClient vs HttpWebResponse? – Josh

+0

Ne me croyez pas sur parole, mais je suppose que HttpClient supportera la négociation du plus haut protocole disponible pour la version de CLR. Ainsi, votre prochain mur de brique nécessitera une mise à niveau de CLR au lieu de la mise à niveau de code. C'est probablement une idée horrible, mais je me demande ce qui se passerait si vous allumer juste tous les bits: 'SecurityProtocolType s = (SecurityProtocolType) 2147483647;' – Crowcoder

Répondre

1

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

La solution qui a fonctionné de mes deux 4.5.2 et 4.7 des applications de test est d'ajouter ce qui suit à App.Config:

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

Voici l'ensemble 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> 
2

Démarrage Avec les applications qui ciblent le .NET Framework 4.7, la valeur par défaut de la propriété ServicePointManager.SecurityProtocol est SecurityProtocolType.SystemDefault.

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

C'est la raison du nouveau comportement vous avez vécu et la nécessité de la nouvelle configuration:

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

Voir here et here