Lakukan panggilan Https menggunakan HttpClient

157

Saya telah menggunakan HttpClientuntuk membuat panggilan WebApi menggunakan C #. Tampak rapi & cepat dibandingkan dengan WebClient. Namun saya terjebak saat melakukan Httpspanggilan.

Bagaimana saya bisa membuat kode di bawah ini untuk melakukan Httpspanggilan?

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: Kode di atas berfungsi dengan baik untuk membuat panggilan http. Tetapi ketika saya mengubah skema ke https tidak berfungsi. Inilah kesalahan yang didapat:

Koneksi yang mendasarinya ditutup: Tidak dapat membangun hubungan saling percaya untuk saluran aman SSL / TLS.

EDIT 2: Mengubah skema ke https adalah: langkah pertama.

Bagaimana saya menyediakan sertifikat & kunci publik / pribadi bersama dengan permintaan C #.

Abhijeet
sumber
2
Anda membuat panggilan https hanya dengan menentukannew Uri("https://foobar.com/");
felickz
2
Saya bingung. Apakah itu belum berfungsi? Apakah Anda mendapatkan kesalahan? (Sunting: Diposting sebelum OP mengubah URI dari https ke http)
Tim

Jawaban:

215

Jika server hanya mendukung versi TLS yang lebih tinggi seperti TLS 1.2 saja, itu masih akan gagal kecuali PC klien Anda dikonfigurasi untuk menggunakan versi TLS yang lebih tinggi secara default. Untuk mengatasi masalah ini tambahkan berikut ini dalam kode Anda.

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

Mengubah kode contoh Anda, itu akan menjadi

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
sumber
@ Derek Senang dan sama-sama. Jika karena alasan tertentu, Anda tidak dapat mengubah kode dalam pengaturan produksi tetapi dapat melakukan beberapa admin di server, saya menggunakan utilitas ini untuk mengkonfigurasi TLS 1.2 sebagai default. nartac.com/Products/IISCrypto
Ronald Ramos
SecurityProtocolType.Tls12tidak dapat menemukan nilai enum yang Anda sebutkan
JobaDiniz
1
@JobaDiniz menggunakan .NET 4.5 atau lebih tinggi dan menyertakan namespace System.Net.
Ronald Ramos
Apakah pengaturan SecurityProtocol hanya perlu terjadi sekali? Suka di startup aplikasi?
CamHart
Ini sangat bagus. Terima kasih. Saya juga menemukan bahwa saya tidak perlu menghapus header yang digunakan klien HttpClient ini = new HttpClient (); ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; HttpResponseMessage response = menunggu client.GetAsync ("https: // ...");
AtLeastTheresToast
127

Cukup tentukan HTTPS di URI.

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

Foobar.com perlu memiliki sertifikat SSL tepercaya atau panggilan Anda akan gagal dengan kesalahan yang tidak tepercaya.

Jawaban EDIT: Sertifikat Klien dengan HttpClient

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

EDIT Answer2: Jika server yang Anda sambungkan telah menonaktifkan SSL, TLS 1.0, dan 1.1 dan Anda masih menjalankan .NET framework 4.5 (atau di bawah), Anda harus menentukan pilihan

  1. Tingkatkan ke .Net 4.6+ ( Mendukung TLS 1.2 secara default )
  2. Tambahkan perubahan registri untuk menginstruksikan 4.5 untuk terhubung melalui TLS1.2 (Lihat: penjualan tenaga untuk compat dan kunci untuk mengubah ATAU checkout IISCrypto melihat Ronald Ramos menjawab komentar )
  3. Tambahkan kode aplikasi untuk secara manual mengkonfigurasi .NET untuk terhubung melalui TLS1.2 (lihat jawaban Ronald Ramos )
Felickz
sumber
@felickz respons yang bagus. apakah ada yang setara dengan perpustakaan WebRequestHandler untuk windows phone 8?
Billatron
@Billatron pustaka yang berbeda untuk WP / Win8 .. lihat
felickz
6
Saat mengembangkan atau berurusan dengan sertifikat yang ditandatangani sendiri, Anda dapat mengabaikan kesalahan sertifikat yang tidak tepercaya dengan yang berikut ini: ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
pengembang
6
Apa GetMyX509Certificate?
Fandi Susanto
6
@developer semoga saja kode tidak masuk ke build produksi Anda :)
felickz
15

Kode Anda harus dimodifikasi dengan cara ini:

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

Anda baru saja menggunakan https:skema URI. Ada halaman yang berguna di sini di MSDN tentang koneksi HTTP aman. Memang:

Gunakan https: skema URI

Protokol HTTP mendefinisikan dua skema URI:

http: Digunakan untuk koneksi yang tidak terenkripsi.

https: Digunakan untuk koneksi aman yang harus dienkripsi. Opsi ini juga menggunakan sertifikat digital dan otoritas sertifikat untuk memverifikasi bahwa server adalah yang diklaimnya.

Selain itu, pertimbangkan bahwa koneksi HTTPS menggunakan sertifikat SSL. Pastikan koneksi aman Anda memiliki sertifikat ini jika tidak, permintaan akan gagal.

EDIT:

Kode di atas berfungsi dengan baik untuk melakukan panggilan http. Tetapi ketika saya mengubah skema menjadi https tidak berfungsi, izinkan saya memposting kesalahan.

Apa artinya itu tidak berhasil? Permintaan gagal? Pengecualian dilemparkan? Jelaskan pertanyaan Anda.

Jika permintaan gagal, maka masalahnya adalah sertifikat SSL.

Untuk memperbaiki masalah ini, Anda bisa menggunakan kelas HttpWebRequestdan kemudian propertinya ClientCertificate. Selanjutnya, Anda dapat menemukan di sini contoh yang berguna tentang cara membuat permintaan HTTPS menggunakan sertifikat.

Contohnya adalah sebagai berikut (seperti yang ditunjukkan pada halaman MSDN yang ditautkan sebelumnya):

//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
sumber
Sebenarnya, triknya terletak pada pengiriman sertifikat bersama dengan permintaan. bagaimana cara melakukannya?
Abhijeet
Di mana mendapatkan "C: \\ mycert.cer"? Bagaimana cara menghasilkan file mycert.cer?
masiboo
@masiboo Apa yang saya tulis menjawab bagaimana melakukan panggilan HTTPS. Tanyakan kepada google tentang cara membuat file * .cer dan Anda akan menemukan jawabannya sendiri.
Alberto Solano
9

Ketika terhubung ke httpssaya mendapat kesalahan ini juga, saya menambahkan baris ini sebelumnya HttpClient httpClient = new HttpClient();dan terhubung dengan sukses:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

Saya tahu itu dari Jawaban Ini dan Anwser Lain yang Mirip dan komentarnya menyebutkan:

Ini adalah retas yang berguna dalam pengembangan sehingga menempatkan # jika DEBUG pernyataan # endif di sekitarnya adalah yang paling harus Anda lakukan untuk membuat ini lebih aman dan menghentikan ini berakhir di produksi

Selain itu, saya tidak mencoba metode dalam Jawaban Lain yang menggunakan new X509Certificate()atau new X509Certificate2()untuk membuat Sertifikat, saya tidak yakin new()apakah hanya akan berhasil atau tidak.

EDIT: Beberapa Referensi:

Buat Sertifikat Server yang Ditandatangani Sendiri di IIS 7

Impor dan Ekspor Sertifikat SSL di IIS 7

Konversikan .pfx ke .cer

Praktik terbaik untuk menggunakan ServerCertificateValidationCallback

Saya menemukan nilai Thumbprint sama dengan x509certificate.GetCertHashString():

Ambil kembali Cap Jempol Sertifikat

yu yang Jian
sumber
6

Saya memiliki masalah yang sama saat menghubungkan ke GitHub, yang membutuhkan agen pengguna. Jadi itu sudah cukup untuk memberikan ini daripada menghasilkan sertifikat

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
sumber
2
Anda harus mencabut token yang telah Anda bagikan dengan internet, saya pikir GitHub mungkin melakukannya secara otomatis.
Amias
21
apakah Anda benar-benar berpikir token saya dimulai dengan 123456789??
Carlo V. Dango
5

Ada pengaturan non-global di tingkat HttpClientHandler:

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

var client = new HttpClient(handler);

Dengan demikian orang mengaktifkan versi TLS terbaru.

Perhatikan, bahwa nilai default SslProtocols.Defaultsebenarnya SslProtocols.Ssl3 | SslProtocols.Tls(diperiksa untuk .Net Core 2.1 dan .Net Framework 4.7.1).

stop-cran
sumber
Terima kasih atas jawabannya. Sedikit catatan: sesuai dokumentasi ini: docs.microsoft.com/en-us/dotnet/api/... Ini membutuhkan setidaknya kerangka 4.7.1.
GELR
@ GELR ya, Anda benar. Kode di atas menghasilkan galat run-time di .Net 4.6.1. Memperbaiki jawabannya.
stop-cran
Dalam versi sebelumnya dari .NET Framework, properti ini bersifat pribadi
JotaBe
Di Net Core 3.1 semua ini berhasil bagi saya. Mengatur System.Net.ServicePointManager.SecurityProtocol = xxx global - memiliki efek nol total dalam jejak paket.
Rowan Smith
3

Hanya menentukan HTTPS di URI harus melakukan trik.

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

Jika permintaan berfungsi dengan HTTP tetapi gagal dengan HTTPS maka ini pasti masalah sertifikat . Pastikan pemanggil mempercayai penerbit sertifikat dan bahwa sertifikat itu tidak kedaluwarsa. Cara cepat dan mudah untuk memeriksa itu adalah dengan mencoba membuat kueri di browser.

Anda juga mungkin ingin memeriksa di server (apakah itu milik Anda dan / atau jika Anda bisa) apakah itu diatur untuk melayani permintaan HTTPS dengan benar.

Crono
sumber
: Saya memiliki masalah serupa: Saya membuat kueri di browser dan sertifikat itu valid (panggilan melewati, disahkan sebagai tingkat layanan dan semua berfungsi seperti pesona) tetapi secara program tidak berfungsi. Apa lagi yang bisa? jika saya menggunakan sertifikat yang sama persis dari browser "secara manual memanggil layanan" daripada dari Aplikasi Web memanggil srvice secara terprogram?
Carlos
2

Saya juga mendapatkan kesalahan:

Koneksi yang mendasarinya ditutup: Tidak dapat membangun hubungan saling percaya untuk saluran aman SSL / TLS.

... dengan aplikasi Xamarin Forms Android yang mencoba meminta sumber daya dari penyedia API yang memerlukan TLS 1.3.

Solusinya adalah memperbarui konfigurasi proyek untuk menukar klien http Xamarin "managed" (.NET) (yang tidak mendukung TLS 1.3 pada Xamarin Forms v2.5), dan sebagai gantinya menggunakan klien asli android.

Ini adalah proyek sederhana beralih di studio visual. Lihat tangkapan layar di bawah ini.

  • Properti Proyek
  • Opsi Android
  • Maju
  • Daftar barang
  • Ubah "Implementasi HttpClient" menjadi "Android"
  • Ubah implementasi SSL / TLS menjadi "Native TLS 1.2+"

masukkan deskripsi gambar di sini

MSC
sumber
1

Tambahkan deklarasi di bawah ini ke kelas Anda:

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

Setelah:

var client = new HttpClient();

Dan:

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

Senang? :)

Greg Stawski
sumber
1

Saya punya masalah ini dan dalam kasus saya solusinya sangat sederhana: buka Visual Studio dengan hak Administrator. Saya mencoba semua solusi di atas dan tidak berhasil sampai saya melakukan ini. Semoga itu menghemat waktu berharga seseorang.

Lucian Satmarean
sumber
Karena Anda baru mengenal situs ini, Anda mungkin tidak tahu bahwa jika jawaban memiliki tanda centang hijau di sebelahnya, itu berarti bahwa jawaban tersebut diterima oleh OP sebagai solusi yang tepat untuk masalahnya. Kecuali jika Anda dapat memberikan jawaban yang lebih baik, lebih lengkap, mungkin lebih baik untuk tidak mengirimkan jawaban lain, terutama pada pertanyaan lama.
Sam W
4
Yah, saya punya masalah juga, dan jawaban yang diperiksa hijau tidak membantu sama sekali. Pikir saya memberikan solusi alternatif yang membantu saya, tapi hei, saya tidak akan melakukannya lain kali. Terima kasih atas poin minusnya;) semoga harimu menyenangkan.
Lucian Satmarean
0

Anda dapat mencoba menggunakan Paket Nugget ModernHttpClient: Setelah mengunduh paket, Anda dapat mengimplementasikannya seperti ini:

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


 handler.ClientCertificateOptions = ClientCertificateOption.Automatic;
 handler.PreAuthenticate = true;
 HttpClient client = new HttpClient(handler);
Uchenna Nnodim
sumber
Sayangnya, ini tidak berhasil dari saya. Solusinya adalah mengaktifkan TLS 1.3 dengan beralih dari klien http yang dikelola xamarin ke klien http Android-asli. Lihat jawaban saya di bawah ini.
MSC
0

Saya setuju dengan felickz tetapi saya juga ingin menambahkan contoh untuk memperjelas penggunaan dalam c #. Saya menggunakan layanan SSL di windows sebagai berikut.

    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;

Jika saya akan menggunakannya dalam aplikasi web, saya hanya mengubah implementasi di sisi proxy seperti ini:

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

Untuk kesalahan:

Koneksi yang mendasarinya ditutup: Tidak dapat membangun hubungan saling percaya untuk saluran aman SSL / TLS.

Saya pikir Anda perlu menerima sertifikat tanpa syarat dengan kode berikut

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

sebagai Oposisi menulis dalam jawaban untuk pertanyaan . NET klien yang terhubung ke ssl Web API .

Nemanja Simović
sumber
4
Ini melewati validasi sertifikat. Jangan pernah melakukan ini dalam produksi.
John Korsnes
Yah @JohnKorsnes, jika Abhijeet mengakses beberapa server WebAPI publik, saya tidak berpikir dia bisa berbuat banyak tentang hal itu. Ini adalah kasus saya.
Nemanja Simović