11 votes

Erreur WebRequest - Impossible de créer un canal sécurisé SSL/TLS

J'essaie d'écrire un code C# qui effectue une requête web contre un point de terminaison d'un service REST utilisé pour calculer la taxe sur les ventes dans une application web. Il s'agit d'un service tiers, sécurisé par SSL. Il y a deux environnements, UAT et production. Le code qui exécute la requête web ressemble à ceci :

...

var req = WebRequest.Create(url) as HttpWebRequest;
req.Method = "POST";
req.ContentType = "application/json";

...

using (var webresponse = req.GetResponse())
{
    using (var responseStream = new StreamReader(webresponse.GetResponseStream()))
    {
        var respJson = responseStream.ReadToEnd();
        calcResult = BuildResponse(calcRequest, respJson, consoleWriteRawReqResponse);
    }
}

return calcResult;

Cela fonctionne parfaitement dans l'environnement UAT. Mais lorsque j'exécute le même code dans l'environnement de production, j'obtiens l'erreur suivante :

"Impossible de créer un canal sécurisé SSL/TLS"

I am capable d'exécuter les deux requêtes à partir de Postman sans problème, sans aucune modification particulière.

Cela m'a conduit à enquêter sur cette erreur, et j'ai trouvé de nombreux messages utiles de l'OS sur le sujet, y compris :

La demande a été interrompue : Impossible de créer un canal sécurisé SSL/TLS

Impossible de créer un canal sécurisé SSL/TLS, malgré le paramétrage de ServerCertificateValidationCallback

Ils m'ont aidé en m'orientant dans la bonne direction, c'est-à-dire en cherchant à définir le paramètre ServicePointManager.SecurityProtocol sur une valeur différente et en utilisant ServicePointManager.ServerCertificateValidationCallback pour enquêter sur les erreurs.

Voici ce que j'ai constaté après avoir joué avec eux :

  • L'appel à l'environnement UAT fonctionnera avec le paramètre par défaut de Ssl3 | Tls (par défaut pour .NET 4.5.2), alors que l'environnement de production ne le sera pas.
  • L'appel de production fonctionnera UNIQUEMENT si je règle ce paramètre sur explicitement à Ssl3 .

Ce code se présente comme suit :

...

var req = WebRequest.Create(url) as HttpWebRequest;
req.Method = "POST";
req.ContentType = "application/json";

...

ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CertValidationCallback);
using (var webresponse = req.GetResponse())
{
    using (var responseStream = new StreamReader(webresponse.GetResponseStream()))
    {
        var respJson = responseStream.ReadToEnd();
        calcResult = BuildResponse(calcRequest, respJson, consoleWriteRawReqResponse);
    }
}
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls;

return calcResult;

C'est d'autant plus déroutant qu'en regardant les points d'extrémité dans un navigateur web, je peux voir qu'ils sont tous les deux sécurisés par le même certificat wildcard et qu'ils utilisent tous les deux TLS 1.0.

Je m'attendais donc à ce que le réglage de ServicePointManager.SecurityProtocol sur TLS fonctionne, mais ce n'est pas le cas.

Je veux vraiment éviter de définir ServicePointManager.SecurityProtocol explicitement à SSL3 parce que notre application est une application web et a plusieurs autres points d'intégration qui communiquent par SSL. Ils fonctionnent tous très bien et je ne veux pas affecter négativement leur fonctionnalité. Même si je définis ce paramètre juste avant l'appel, et que je le modifie juste après, je risque de rencontrer des problèmes de concurrence puisque ServicePointManager.SecurityProtocol est statique.

J'ai également enquêté sur ce sujet et je n'ai pas aimé ce que j'ai lu. Il est fait mention de l'utilisation de différents domaines d'application :

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

Comment utiliser SSL3 au lieu de TLS dans un HttpWebRequest particulier ?

Mais cela me semble trop complexe ou trop compliqué. Est-ce que la création d'un domaine d'application est vraiment la seule solution ? Ou est-ce que c'est quelque chose que je ne devrais tout simplement pas essayer de résoudre et plutôt en parler avec le propriétaire du service en question ? Il est très curieux pour moi que cela fonctionne avec TLS sur un environnement / serveur, mais pas sur l'autre.

EDIT J'ai fait quelques essais supplémentaires. J'ai modifié mon client pour utiliser l'approche décrite dans ce billet de blog (en utilisant un domaine d'application différent pour isoler le code qui modifie le ServicePointManager.SecurityProtocol) :

https://bitlush.com/blog/executing-code-in-a-separate-application-domain-using-c-sharp

Cela a en fait très bien fonctionné et pourrait être une solution de repli. Mais j'ai également appris que le fournisseur du service en question dispose d'un point de terminaison différent (même URL, port différent) qui est sécurisé à l'aide de TLS 1.2. Heureusement, en élargissant mon paramètre SecurityProtocol comme suit dans l'événement de démarrage de l'application global.asax.cs :

ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

Je suis capable de communiquer avec le service dans tous les environnements. Cela n'affecte pas non plus mes intégrations existantes avec d'autres services (CyberSource, par exemple).

Cependant, une nouvelle question se pose à présent, mais elle est liée à la précédente. Pourquoi Est-ce que cet appel ne fonctionne que si je développe SecurityProtocolType comme indiqué ci-dessus ? Mes autres intégrations, comme CyberSource, n'exigeaient pas cela. Pourtant, celle-ci l'exige. Et elles semblent toutes être sécurisées en utilisant TLS 1.2 d'après ce que j'ai vu dans le navigateur.

7voto

Rafael Pereira Points 21

Si vous utilisez la version 4.0, vous pouvez l'utiliser comme suit :

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; // SecurityProtocolType.Tls12

0voto

Todd Points 2386

Certaines configurations avancées de TLS sur un serveur web sont cachées. Votre serveur de production a probablement été modifié pour se protéger contre les attaques DROWN, logjam, FREAK, POODLE et BEAST.

voir

Pour modifier ces paramètres TLS avancés, il ne suffit pas de cliquer sur quelques boutons dans IIS. Enfin, cela peut être aussi simple si vous utilisez un outil tiers comme celui-ci : https://www.nartac.com/Products/IISCrypto

Ces configurations fonctionnent bien pour les principaux navigateurs web récents, mais .Net semble avoir des difficultés avec ces configurations de serveurs sécurisés modernes (à moins que vous ne remplaciez manuellement les valeurs par défaut, comme vous l'avez découvert).

Conclusion : ce n'est pas évident, vos environnements UAT et de production semblent identiques, mais ils ne le sont pas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X