Requêtes .NET https avec différents protocoles de sécurité sur les threads

Je gère une application ASP.NET assez complexe (un NopCommerce 3.10 personnalisé). Il doit se connecter à des serveurs tiers via HTTPS selon différents scénarios. Je le fais via la classe HttpWebRequest .

Certains de ces serveurs sont mal configurés:

L’un des serveurs tiers (par exemple, le serveur A ) requirejs le type de protocole SSL3 et échoue simplement la connexion si un autre type de protocole est défini. Un autre serveur (par exemple, le serveur B ) fournit un certificate incorrect si la connexion est établie avec SSL3. Plus précisément, il fournit un certificate avec un mauvais CN (nom commun). Cependant, si j’utilise TLS depuis le début, le certificate est OK.

J’ai déterminé le problème ci-dessus à l’aide du rappel ServicePointManager.ServerCertificateValidationCallback pour vérifier l’erreur de stratégie SSL.

La modification du protocole de sécurité est effectuée via ServicePointManager.SecurityProtocol, qui est une propriété statique. Cependant, les demandes effectuées par les clients à mon application qui déclenchent les connexions HTTPS décrites ci-dessus peuvent être exécutées en parallèle dans différents threads.

Si, par exemple, je règle le protocole de sécurité sur le type souhaité, exécute la demande HTTPS, puis le rétablit pour le serveur A , je ne peux pas garantir que le fait qu’une demande ait besoin de se connecter au serveur B ne change pas ServicePointManager.SecurityProtocol à une valeur autre que celle requirejse par le serveur A. Je crois que c’est un problème multi-threading typique avec des variables statiques.

De mes recherches, j’ai déterminé que .NET ne fournit pas un moyen d’utiliser un protocole SSL spécifique pour chaque instance WebRequest.

Je pense à des solutions telles que:

  • mettre en queue toutes les connexions HTTPS sortantes au sein de mon application pour garantir le bon protocole SSL pour chacune d’entre elles
  • construction d’un domaine d’application distinct pour chaque demande HTTPS (suggéré par https://stackoverflow.com/a/3107692/1288522 )
  • changer la demande HTTPS en connexions TCP de bas niveau et appliquer différents protocoles SSL pour chacune d’entre elles
  • faire une application proxy asp.net qui mettra en queue les requêtes sortantes

Remarque: la mise en queue ne serait pas un énorme problème de performances, car un faible pourcentage de toutes les demandes des clients parvient au code en question.

Les solutions ci-dessus nécessitent toutefois une refactorisation difficile compte tenu de l’architecture de l’application ou des solutions de contournement approximatives (troisième solution).

Ma question est très similaire à celle sur MSDN , mais celle-ci n’a pas obtenu de réponses satisfaisantes.

Existe-t-il un moyen plus simple ou plus efficace de s’assurer que chaque demande https utilise un protocole SSL spécifique?

Nous avons rencontré le même problème et avons opté pour l’approche de domaine d’application que vous avez mentionnée, mettant en œuvre une solution basée sur ce qui est proposé ici, qui est une très belle description de la gestion de l’exécution du code dans un domaine d’application distinct:

http://www.superstarcoders.com/blogs/posts/executing-code-in-a-separate-application-domain-using-c-sharp.aspx

Nous utilisons sa classe isolée à peu près telle quelle:

  public sealed class Isolated : IDisposable where T : MarshalByRefObject { private AppDomain _domain; private readonly T _value; public Isolated() { _domain = AppDomain.CreateDomain("Isolated:" + Guid.NewGuid(), null, AppDomain.CurrentDomain.SetupInformation); var type = typeof(T); _value = (T)_domain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName); } public T Value { get { return _value; } } public void Dispose() { if (_domain == null) return; AppDomain.Unload(_domain); _domain = null; } } 

Et puis nous avons un wrapper autour du WebClient standard, qui permet de paramétrer le protocole:

 public class WebClient : MarshalByRefObject, IWebClient { public WebClientResponse GetResponse(ssortingng address) { return GetResponse(address, null); } public WebClientResponse GetResponse(ssortingng address, ssortingng securityProtocol) { if (!ssortingng.IsNullOrWhiteSpace(securityProtocol)) ServicePointManager.SecurityProtocol = (SecurityProtocolType)Enum.Parse(typeof(SecurityProtocolType), securityProtocol); var response = new WebClientResponse(); try { using (var wc = new System.Net.WebClient()) { //  } } catch (Exception ex) { response.Exception = new GetResponseException(ssortingng.Format("Unable to get response from {0}", address), ex); } return response; } } [Serializable] public class WebClientResponse { public Exception Exception { get; set; } public ssortingng Response { get; set; } } [Serializable] public class GetResponseException : Exception { public GetResponseException(ssortingng message, Exception innerException) : base(message, innerException) { } public GetResponseException(SerializationInfo info, StreamingContext context) : base(info, context) { } } 

En les liant, nous avons un code qui détermine s’il doit remplacer le protocole actuellement défini. Si tel est le cas, il lance le domaine d’application isolé, sinon il utilise un WebClient existant:

 ... WebClientResponse webClientResponse; if (!ssortingng.IsNullOrWhiteSpace(ForceSecurityProtocol)) { using (var isolated = new Isolated()) { webClientResponse = isolated.Value.GetResponse(url, ForceSecurityProtocol); } } else { webClientResponse = _webClient.GetResponse(url); } ... 

Notez que notre application ne s’inscrit pas dans un domaine de débit extrêmement élevé. Par conséquent, quel que soit le prix de performance que nous payons avec cette approche, cela n’a pas vraiment d’impact. Si nous voulions mettre quelque chose comme cela à un endroit où il y avait beaucoup de trafic dans notre application Web, nous aurions fait des tests.

Vous pouvez simplement utiliser le rappel que vous avez mentionné ( ServicePointManager.ServerCertificateValidationCallback ) pour implémenter une logique de validation personnalisée: vous ne contournez les erreurs que si elles proviennent de ce serveur malveillant .