web-dev-qa-db-fra.com

Faire un appel Https en utilisant HttpClient

J'utilise HttpClient pour passer des appels WebApi à l'aide de C #. Semble soigné et rapide comparé à WebClient. Cependant, je suis coincé lorsque je passe des appels Https.

Comment puis-je faire le code ci-dessous pour passer des appels Https?

HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("https://foobar.com/");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(
                new MediaTypeWithQualityHeaderValue("application/xml"));

var task = httpClient.PostAsXmlAsync<DeviceRequest>(
                "api/SaveData", request);

EDIT 1: Le code ci-dessus fonctionne bien pour les appels http. Mais lorsque je modifie le schéma en https, cela ne fonctionne pas. Voici l'erreur obtenue:

La connexion sous-jacente était fermée: Impossible d'établir une relation de confiance pour le canal sécurisé SSL/TLS.

EDIT 2: Changer le schéma en https est: première étape.

Comment puis-je fournir le certificat et la clé publique/privée avec la demande C #.

134
Abhijeet

Si le serveur ne prend en charge que les versions TLS supérieures, telles que TLS 1.2, le système échouera, sauf si votre ordinateur client est configuré pour utiliser une version supérieure de TLS par défaut. Pour résoudre ce problème, ajoutez ce qui suit dans votre code.

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

Modifier votre exemple de code, ce serait

HttpClient httpClient = new HttpClient();   

//specify to use TLS 1.2 as default connection
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

httpClient.BaseAddress = new Uri("https://foobar.com/");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));

var task = httpClient.PostAsXmlAsync<DeviceRequest>("api/SaveData", request);
170
Ronald Ramos

Spécifiez simplement HTTPS dans l'URI.

new Uri("https://foobar.com/");

Foobar.com devra disposer d'un certificat SSL de confiance ou vos appels échoueront avec une erreur non fiable.

EDIT Answer: ClientCertificates with HttpClient

WebRequestHandler handler = new WebRequestHandler();
X509Certificate2 certificate = GetMyX509Certificate();
handler.ClientCertificates.Add(certificate);
HttpClient client = new HttpClient(handler);

EDIT Answer2: Si le serveur auquel vous vous connectez a désactivé SSL, TLS 1.0 et 1.1 et que vous utilisez toujours .NET Framework 4.5 (ou une version inférieure), vous devez choisir

  1. Mise à niveau vers .Net 4.6+ ( Prend en charge TLS 1.2 par défaut )
  2. Ajoutez des modifications de registre pour indiquer à 4.5 de se connecter via TLS1.2 (voir: rédaction de Salesforce pour compat et les clés de modification OR paiement IISCrypto voir Ronald Ramos - répondre aux commentaires )
  3. Ajoutez le code d'application pour configurer manuellement .NET afin qu'il se connecte via TLS1.2 (voir Ronald Ramos answer )
122
felickz

Votre code devrait être modifié de cette façon:

httpClient.BaseAddress = new Uri("https://foobar.com/");

Il vous suffit d'utiliser le schéma https: URI. Il existe une page utile ici sur MSDN à propos des connexions HTTP sécurisées. En effet:

Utiliser le schéma https: URI

Le protocole HTTP définit deux schémas d'URI:

http: utilisé pour les connexions non chiffrées.

https: utilisé pour les connexions sécurisées à chiffrer. Cette option utilise également des certificats numériques et des autorités de certification pour vérifier que le serveur est bien ce qu'il prétend être.

De plus, considérez que les connexions HTTPS utilisent un certificat SSL. Assurez-vous que votre connexion sécurisée possède ce certificat, sinon les demandes échoueront.

EDIT:

Le code ci-dessus fonctionne bien pour passer des appels http. Mais lorsque je modifie le schéma en https, cela ne fonctionne pas, laissez-moi poster l'erreur.

Qu'est-ce que cela signifie ne fonctionne pas? Les demandes échouent? Une exception est levée? Clarifiez votre question.

Si les demandes échouent, le problème devrait être le certificat SSL.

Pour résoudre le problème, vous pouvez utiliser la classe HttpWebRequest , puis sa propriété ClientCertificate. En outre, vous pouvez trouver ici un exemple utile sur la manière de faire une demande HTTPS à l'aide du certificat.

Voici un exemple (comme indiqué dans la page MSDN liée précédemment):

//You must change the path to point to your .cer file location. 
X509Certificate Cert = X509Certificate.CreateFromCertFile("C:\\mycert.cer");
// Handle any certificate errors on the certificate from the server.
ServicePointManager.CertificatePolicy = new CertPolicy();
// You must change the URL to point to your Web server.
HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("https://YourServer/sample.asp");
Request.ClientCertificates.Add(Cert);
Request.UserAgent = "Client Cert Sample";
Request.Method = "GET";
HttpWebResponse Response = (HttpWebResponse)Request.GetResponse();
13
Alberto Solano

J'ai eu le même problème lors de la connexion à GitHub, qui nécessite un agent utilisateur. Il suffit donc de fournir ceci plutôt que de générer un certificat

var client = new HttpClient();

client.BaseAddress = new Uri("https://api.github.com");
client.DefaultRequestHeaders.Add(
    "Authorization",
    "token 123456789307d8c1d138ddb0848ede028ed30567");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add(
    "User-Agent",
    "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36");
6
Carlo V. Dango

Lorsque je me connecte à https J'ai aussi cette erreur, j'ajoute cette ligne avant HttpClient httpClient = new HttpClient(); et me connecte avec succès:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

Je le connais depuis cette réponse et ne autre réponse similaire et le commentaire mentionne:

C’est un hack utile en développement, donc ajouter une déclaration #if DEBUG #endif est le moins que vous puissiez faire pour rendre cela plus sûr et arrêter cette production.

De plus, je n'ai pas essayé la méthode dans autre réponse qui utilise new X509Certificate() ou new X509Certificate2() pour créer un certificat, je ne suis pas sûr de simplement créer par new() travaillera ou pas.

EDIT: Quelques références:

Créer un certificat de serveur auto-signé dans IIS 7

Importer et exporter des certificats SSL dans IIS 7

Convertir .pfx en .cer

Meilleures pratiques pour l'utilisation de ServerCertificateValidationCallback

Je trouve que la valeur de Thumbprint est égale à x509certificate.GetCertHashString():

Récupérer l'empreinte numérique d'un certificat

5
yu yang Jian

Spécifier simplement HTTPS dans l'URI devrait suffire.

httpClient.BaseAddress = new Uri("https://foobar.com/");

Si la demande fonctionne avec HTTP mais échoue avec HTTPS, alors il s'agit très certainement d'un problème de certificat. Assurez-vous que l'appelant approuve l'émetteur du certificat et que le certificat n'a pas expiré. Un moyen simple et rapide de vérifier cela consiste à essayer de créer la requête dans un navigateur.

Vous pouvez également vérifier sur le serveur (s'il vous appartient et/ou si vous le pouvez) qu'il est configuré pour traiter correctement les demandes HTTPS.

3
Crono

Je recevais aussi l'erreur:

La connexion sous-jacente était fermée: Impossible d'établir une relation de confiance pour le canal sécurisé SSL/TLS.

... avec un Xamarin Forms Android - application de ciblage essayant de demander des ressources à un fournisseur d'API nécessitant TLS 1.3 .

La solution consistait à mettre à jour la configuration du projet pour échanger le client http "géré" (.NET) Xamarin (qui ne prend pas en charge TLS 1.3 à partir de Xamarin Forms v2.5), mais plutôt utiliser le Android. client natif.

C'est un simple projet bascule en studio visuel. Voir la capture d'écran ci-dessous.

  • Propriétés du projet
  • Options Android
  • Avancée
  • Élément de liste
  • Remplacez "Implémentation HttpClient" par "Android".
  • Changer l'implémentation SSL/TLS en "Native TLS 1.2+"

enter image description here

1
MSC

Il existe un paramètre non global au niveau de HttpClientHandler:

var handler = new HttpClientHandler()
{
    SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls
};

var client = new HttpClient(handler);

Ainsi, on active les dernières versions de TLS.

Notez que la valeur par défaut SslProtocols.Default est en fait SslProtocols.Ssl3 | SslProtocols.Tls (vérifiée pour .Net Core 2.1 et .Net Framework 4.7.1).

0
stop-cran

Ajoutez les déclarations ci-dessous à votre classe:

public const SslProtocols _Tls12 = (SslProtocols)0x00000C00;
public const SecurityProtocolType Tls12 = (SecurityProtocolType)_Tls12;

Après:

var client = new HttpClient();

Et:

ServicePointManager.SecurityProtocol = Tls12;
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 /*| SecurityProtocolType.Tls */| Tls12;

Content? :)

0
Greg Stawski

Vous pouvez essayer d'utiliser le package ModernHttpClient Nuget: après avoir téléchargé le package, vous pouvez le mettre en œuvre de la manière suivante:

 var handler = new ModernHttpClient.NativeMessageHandler()
 {
     UseProxy = true,
 };


 handler.ClientCertificateOptions = ClientCertificateOption.Automatic;
 handler.PreAuthenticate = true;
 HttpClient client = new HttpClient(handler);
0
Uchenna Nnodim

Je suis d’accord avec felickz mais j’aimerais aussi ajouter un exemple pour clarifier l’utilisation de c #. J'utilise SSL dans le service Windows comme suit.

    var certificatePath = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "bin");
    gateway = new GatewayService();
    gateway.PreAuthenticate = true;


    X509Certificate2 cert = new X509Certificate2(certificatePath + @"\Attached\my_certificate.pfx","certificate_password");
    gateway.ClientCertificates.Add(cert);

    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
    gateway.UserAgent = Guid.NewGuid().ToString();
    gateway.Timeout = int.MaxValue;

Si je vais l'utiliser dans une application Web, je change simplement l'implémentation du côté du proxy comme ceci:

public partial class GatewayService : System.Web.Services.Protocols.SoapHttpClientProtocol // to => Microsoft.Web.Services2.WebServicesClientProtocol
0
Hamit YILDIRIM