Https-Aufruf mit HttpClient

157

Ich habe verwendet, HttpClientum WebApi-Aufrufe mit C # zu tätigen. Scheint ordentlich und schnell im Vergleich zu WebClient. Ich stecke jedoch fest, während ich Httpstelefoniere.

Wie kann ich den folgenden Code verwenden, um HttpsAnrufe zu tätigen?

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);

BEARBEITEN 1: Der obige Code funktioniert gut für http-Aufrufe. Aber wenn ich das Schema in https ändere, funktioniert es nicht. Hier ist der Fehler erhalten:

Die zugrunde liegende Verbindung wurde geschlossen: Es konnte keine Vertrauensbeziehung für den sicheren SSL / TLS-Kanal hergestellt werden.

BEARBEITEN 2: Das Ändern des Schemas in https ist: Schritt eins.

Wie stelle ich ein Zertifikat und einen öffentlichen / privaten Schlüssel zusammen mit einer C # -Anforderung bereit?

Abhijeet
quelle
2
Sie tätigen https-Anrufe, indem Sie nur new Uri("https://foobar.com/");
angeben
2
Ich bin verwirrt. Funktioniert das nicht schon Erhalten Sie einen Fehler? (Bearbeiten: Gepostet, bevor das OP den URI von https in http geändert hat)
Tim

Antworten:

214

Wenn der Server nur eine höhere TLS-Version wie nur TLS 1.2 unterstützt, schlägt dies weiterhin fehl, es sei denn, Ihr Client-PC ist standardmäßig für die Verwendung einer höheren TLS-Version konfiguriert. Um dieses Problem zu beheben, fügen Sie Folgendes in Ihren Code ein.

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

Wenn Sie Ihren Beispielcode ändern, ist dies der Fall

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);
Ronald Ramos
quelle
@DerekS Bin froh und du bist willkommen. Wenn Sie aus irgendeinem Grund den Code in der Produktionseinstellung nicht ändern können, aber einige Administratoren auf dem Server ausführen können, verwende ich dieses Dienstprogramm, um TLS 1.2 als Standard zu konfigurieren. nartac.com/Products/IISCrypto
Ronald Ramos
SecurityProtocolType.Tls12konnte die von Ihnen erwähnten Aufzählungswerte nicht finden
JobaDiniz
1
@JobaDiniz verwendet .NET 4.5 oder höher und enthält den System.Net-Namespace.
Ronald Ramos
Muss das Festlegen von SecurityProtocol nur einmal erfolgen? Wie beim Start der Anwendung?
CamHart
Das funktioniert super. Vielen Dank. Ich fand auch, dass ich keine Header löschen musste, die diesen HttpClient-Client verwendeten = new HttpClient (); ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; HttpResponseMessage response = warte auf client.GetAsync ("https: // ...");
AtLeastTheresToast
127

Geben Sie einfach HTTPS in der URI an.

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

Foobar.com muss über ein vertrauenswürdiges SSL-Zertifikat verfügen, sonst schlagen Ihre Anrufe mit einem nicht vertrauenswürdigen Fehler fehl.

EDIT Antwort: ClientCertificates mit HttpClient

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

BEARBEITEN Antwort 2: Wenn der Server, zu dem Sie eine Verbindung herstellen, SSL, TLS 1.0 und 1.1 deaktiviert hat und Sie noch .NET Framework 4.5 (oder niedriger) ausführen, müssen Sie eine Auswahl treffen

  1. Upgrade auf .Net 4.6+ ( unterstützt standardmäßig TLS 1.2 )
  2. Fügen Sie Registrierungsänderungen hinzu, um 4.5 anzuweisen, eine Verbindung über TLS1.2 herzustellen (siehe: Salesforce-Beschreibung für Kompatibilität und Schlüssel zum Ändern ODER Auschecken von IISCrypto, siehe Ronald Ramos, Antwortkommentare )
  3. Fügen Sie Anwendungscode hinzu, um .NET manuell für die Verbindung über TLS1.2 zu konfigurieren (siehe Antwort von Ronald Ramos ).
felickz
quelle
@felickz tolle Antwort. Gibt es eine Entsprechung zur WebRequestHandler-Bibliothek für Windows Phone 8?
Billatron
@ Billatron verschiedene Bibliotheken für WP / Win8 .. siehe
felickz
5
Wenn Sie selbstsignierte Zertifikate entwickeln oder damit umgehen, können Sie nicht vertrauenswürdige Zertifizierungsfehler wie folgt ignorieren: ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
Entwickler
6
Was ist GetMyX509Certificate?
Fandi Susanto
6
@ Entwickler entwickeln nur hoffen, dass Code nicht in Ihre Produktion Build
rutscht
15

Ihr Code sollte folgendermaßen geändert werden:

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

Sie müssen nur das https:URI-Schema verwenden. Es gibt eine nützliche Seite hier auf MSDN über die sicheren HTTP - Verbindungen. Tatsächlich:

Verwenden Sie das https: URI-Schema

Das HTTP-Protokoll definiert zwei URI-Schemata:

http: Wird für unverschlüsselte Verbindungen verwendet.

https: Wird für sichere Verbindungen verwendet, die verschlüsselt werden sollen. Diese Option verwendet auch digitale Zertifikate und Zertifizierungsstellen, um zu überprüfen, ob der Server der ist, für den er sich ausgibt.

Beachten Sie außerdem, dass die HTTPS-Verbindungen ein SSL-Zertifikat verwenden. Stellen Sie sicher, dass Ihre sichere Verbindung über dieses Zertifikat verfügt, da sonst die Anforderungen fehlschlagen.

BEARBEITEN:

Der obige Code funktioniert gut für http-Aufrufe. Wenn ich das Schema jedoch in https ändere, funktioniert es nicht. Lassen Sie mich den Fehler veröffentlichen.

Was bedeutet, dass es nicht funktioniert? Die Anfragen schlagen fehl? Eine Ausnahme wird ausgelöst? Klären Sie Ihre Frage.

Wenn die Anforderungen fehlschlagen, sollte das Problem das SSL-Zertifikat sein.

Um das Problem zu beheben, können Sie die Klasse HttpWebRequestund dann ihre Eigenschaft verwenden ClientCertificate. Darüber hinaus finden Sie hier ein nützliches Beispiel zum Erstellen einer HTTPS-Anforderung mithilfe des Zertifikats.

Ein Beispiel ist das folgende (wie auf der zuvor verlinkten MSDN-Seite gezeigt):

//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();
Alberto Solano
quelle
Der Trick liegt genau darin, Zertifikate zusammen mit der Anfrage zu senden. wie geht das?
Abhijeet
Wo bekomme ich "C: \\ mycert.cer"? Wie generiere ich die Datei mycert.cer?
Masiboo
@masiboo Was ich geschrieben habe, ist die Beantwortung von HTTPS-Anrufen. Wenn Sie Google fragen, wie Sie eine * .cer-Datei erstellen, finden Sie die Antwort selbst.
Alberto Solano
9

Beim Verbinden mit habe httpsich auch diesen Fehler erhalten, füge ich diese Zeile vorher hinzu HttpClient httpClient = new HttpClient();und verbinde erfolgreich:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

Ich kenne es aus dieser Antwort und einem anderen ähnlichen Anwser und der Kommentar erwähnt:

Dies ist ein Hack, der in der Entwicklung nützlich ist. Daher ist es das Mindeste, was Sie tun sollten, um dies sicherer zu machen und zu verhindern, dass dies in der Produktion endet, wenn Sie eine # if DEBUG # endif-Anweisung darum setzen

Außerdem habe ich die Methode in einer anderen Antwort , die ein Zertifikat verwendet new X509Certificate()oder erstellt new X509Certificate2(), nicht ausprobiert. Ich bin mir nicht sicher, ob es einfach new()funktioniert oder nicht.

EDIT: Einige Referenzen:

Erstellen Sie ein selbstsigniertes Serverzertifikat in IIS 7

Importieren und Exportieren von SSL-Zertifikaten in IIS 7

Konvertieren Sie .pfx in .cer

Best Practices für die Verwendung von ServerCertificateValidationCallback

Ich finde, der Wert von Thumbprint ist gleich x509certificate.GetCertHashString():

Rufen Sie den Fingerabdruck eines Zertifikats ab

Yu Yang Jian
quelle
6

Ich hatte das gleiche Problem beim Herstellen einer Verbindung zu GitHub, für das ein Benutzeragent erforderlich ist. Daher ist es ausreichend, dies bereitzustellen, anstatt ein Zertifikat zu generieren

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");
Carlo V. Dango
quelle
2
Sie sollten das Token, das Sie mit dem Internet geteilt haben, widerrufen. Ich denke, GitHub hat dies möglicherweise automatisch getan.
Amias
21
Glaubst du wirklich, mein Token beginnt mit 123456789?
Carlo V. Dango
5

Es gibt eine nicht globale Einstellung auf der Ebene von HttpClientHandler:

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

var client = new HttpClient(handler);

Somit werden die neuesten TLS-Versionen aktiviert.

Beachten Sie, dass der Standardwert SslProtocols.Defaulttatsächlich ist SslProtocols.Ssl3 | SslProtocols.Tls( aktiviert für .Net Core 2.1 und .Net Framework 4.7.1).

Stop-Cran
quelle
Danke für die Antwort. Ein kleiner Hinweis: Gemäß dieser Dokumentation: docs.microsoft.com/en-us/dotnet/api/… Es ist mindestens Framework 4.7.1 erforderlich.
GELR
@GELR ja du hast recht Der obige Code führt zu einem Laufzeitfehler in .Net 4.6.1. Die Antwort wurde korrigiert.
Stop-Cran
In früheren Versionen von .NET Framework ist diese Eigenschaft privat
JotaBe
Auf Net Core 3.1 hat das alles für mich funktioniert. Das Festlegen des globalen System.Net.ServicePointManager.SecurityProtocol = xxx - hatte in einer Paketverfolgung absolut keine Auswirkung.
Rowan Smith
3

Nur die Angabe von HTTPS in der URI sollte den Trick tun.

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

Wenn die Anforderung mit HTTP funktioniert, aber mit HTTPS fehlschlägt, handelt es sich mit Sicherheit um ein Zertifikatproblem . Stellen Sie sicher, dass der Anrufer dem Zertifikatsaussteller vertraut und das Zertifikat nicht abgelaufen ist. Eine schnelle und einfache Möglichkeit, dies zu überprüfen, besteht darin, die Abfrage in einem Browser durchzuführen.

Möglicherweise möchten Sie auch auf dem Server überprüfen (ob er Ihnen gehört und / oder ob Sie dies können), ob er so eingestellt ist, dass HTTPS-Anforderungen ordnungsgemäß verarbeitet werden.

Crono
quelle
: Ich habe ein ähnliches Problem: Ich habe die Abfrage im Browser durchgeführt und das Zertifikat ist gültig (Anruf wird weitergeleitet, als Service Level autorisiert und alles funktioniert wie ein Zauber), aber programmgesteuert funktioniert es nicht. Was kann noch sein? Wenn ich vom Browser "Manuelles Aufrufen des Dienstes" genau dasselbe Zertifikat verwende wie von der Webanwendung, die den Dienst programmgesteuert aufruft?
Carlos
2

Ich bekam auch den Fehler:

Die zugrunde liegende Verbindung wurde geschlossen: Es konnte keine Vertrauensbeziehung für den sicheren SSL / TLS-Kanal hergestellt werden.

... mit einer Xamarin Forms Android- Targeting-Anwendung, die versucht, Ressourcen von einem API-Anbieter anzufordern, für den TLS 1.3 erforderlich ist .

Die Lösung bestand darin, die Projektkonfiguration zu aktualisieren, um den von Xamarin "verwalteten" (.NET) http-Client (der TLS 1.3 ab Xamarin Forms v2.5 nicht unterstützt) auszutauschen und stattdessen den nativen Android-Client zu verwenden.

Es ist ein einfacher Projektwechsel im Visual Studio. Siehe Screenshot unten.

  • Projekteigenschaften
  • Android-Optionen
  • Fortgeschrittene
  • Listenpunkt
  • Ändern Sie "HttpClient-Implementierung" in "Android"
  • Ändern Sie die SSL / TLS-Implementierung in "Native TLS 1.2+".

Geben Sie hier die Bildbeschreibung ein

MSC
quelle
1

Fügen Sie Ihrer Klasse die folgenden Deklarationen hinzu:

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

Nach dem:

var client = new HttpClient();

Und:

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

Glücklich? :) :)

Greg Stawski
quelle
1

Ich hatte dieses Problem und in meinem Fall war die Lösung dumm einfach: Öffnen Sie Visual Studio mit Administratorrechten. Ich habe alle oben genannten Lösungen ausprobiert und es hat nicht funktioniert, bis ich dies getan habe. Hoffe, es spart jemandem wertvolle Zeit.

Lucian Satmarean
quelle
Da Sie neu auf der Website sind, wissen Sie möglicherweise nicht, dass eine Antwort mit dem grünen Häkchen daneben von OP als die richtige Lösung für ihr Problem akzeptiert wurde. Wenn Sie keine bessere und vollständigere Antwort geben können, ist es wahrscheinlich am besten, keine weitere Antwort einzureichen, insbesondere bei einer so alten Frage.
Sam W
4
Nun, ich hatte auch das Problem und die grün markierte Antwort half überhaupt nicht. Ich dachte, ich gebe eine alternative Lösung, die mir geholfen hat, aber hey, ich werde es das nächste Mal nicht tun. Danke für die Minuspunkte;) Ich wünsche dir einen schönen Tag.
Lucian Satmarean
0

Sie können versuchen, das ModernHttpClient Nuget-Paket zu verwenden: Nachdem Sie das Paket heruntergeladen haben, können Sie es folgendermaßen implementieren:

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


 handler.ClientCertificateOptions = ClientCertificateOption.Automatic;
 handler.PreAuthenticate = true;
 HttpClient client = new HttpClient(handler);
Uchenna Nnodim
quelle
Leider hat das bei mir nicht geklappt. Die Lösung bestand darin, TLS 1.3 zu aktivieren, indem vom von xamarin verwalteten http-Client zum android-nativen http-Client gewechselt wurde. Siehe meine Antwort unten.
MSC
0

Ich stimme felickz zu, möchte aber auch ein Beispiel zur Verdeutlichung der Verwendung in c # hinzufügen. Ich verwende SSL im Windows-Dienst wie folgt.

    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;

Wenn ich es in einer Webanwendung verwenden möchte, ändere ich die Implementierung auf der Proxyseite wie folgt:

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

Bei Fehler:

Die zugrunde liegende Verbindung wurde geschlossen: Es konnte keine Vertrauensbeziehung für den sicheren SSL / TLS-Kanal hergestellt werden.

Ich denke, dass Sie das Zertifikat mit folgendem Code unbedingt akzeptieren müssen

ServicePointManager.ServerCertificateValidationCallback += 
    (sender, cert, chain, sslPolicyErrors) => true;

wie Oppositional in seiner Antwort auf die Frage schrieb .NET-Client, der eine Verbindung zur SSL-Web-API herstellt .

Nemanja Simović
quelle
4
Dies umgeht die Zertifizierungsvalidierung. Tun Sie dies niemals in der Produktion.
John Korsnes
Nun, @ JohnKorsnes, wenn Abhijeet auf einen öffentlichen WebAPI-Server zugreift, denke ich nicht, dass er viel dagegen tun kann. Das war mein Fall.
Nemanja Simović