Сделать вызов Https с помощью HttpClient

Я использую HttpClient для выполнения вызовов WebApi с использованием С#. Кажется аккуратным и быстрым способом по сравнению с WebClient. Однако я застрял во время звонков Https.

Как я могу сделать приведенный ниже код для совершения звонков 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);

РЕДАКТИРОВАТЬ 1: приведенный выше код отлично работает для http-звонков. Но когда я меняю схему на https, она не работает. Вот полученная ошибка:

Базовое соединение было закрыто: не удалось установить доверительные отношения для безопасного канала SSL/TLS.

РЕДАКТИРОВАТЬ 2: Изменение схемы на https: шаг первый.

Как мне предоставить сертификат и открытый/закрытый ключ вместе с С# запросом.

Ответ 1

Если сервер поддерживает только более высокую версию TLS, например TLS 1.2, она все равно будет работать, если ваш клиентский ПК не настроен на использование более высокой версии TLS по умолчанию. Чтобы решить эту проблему, добавьте в свой код следующее.

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

Изменив код примера, это будет

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

Ответ 2

Просто укажите HTTPS в URI.

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

Foobar.com должен будет иметь доверенный сертификат SSL, или ваши вызовы не будут выполнены с ненадежной ошибкой.

EDIT Ответ: ClientCertificates с HttpClient

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

EDIT Answer2: Если подключенный к серверу отключил SSL, TLS 1.0 и 1.1, и вы все еще используете .NET framework 4.5 (или ниже), вам нужно сделать выбор

Ответ 3

Ваш код должен быть изменен следующим образом:

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

Вы должны использовать схему URI https:. Здесь есть полезная страница здесь в MSDN об защищенных HTTP-соединениях. Действительно:

Используйте схему https: URI

Протокол HTTP определяет две схемы URI:

http: используется для незашифрованных соединений.

https: Используется для защищенных соединений, которые должны быть зашифрованы. Этот параметр также использует цифровые сертификаты и органы сертификации, чтобы убедиться, что сервер является тем, кем он себя утверждает.

Кроме того, учтите, что HTTPS-соединения используют сертификат SSL. Убедитесь, что ваше безопасное соединение имеет этот сертификат, иначе запросы не удастся.

EDIT:

Над кодом работает отлично для создания http-звонков. Но когда я меняю схема https не работает, позвольте мне опубликовать сообщение об ошибке.

Что это значит, не работает? Запросы терпят неудачу? Исключено ли исключение? Уточните свой вопрос.

Если запросы терпят неудачу, то проблема должна быть SSL-сертификатом.

Чтобы устранить проблему, вы можете использовать класс HttpWebRequest, а затем его свойство ClientCertificate. Кроме того, вы можете найти здесь полезный пример того, как сделать запрос HTTPS, используя сертификат.

Пример следующий (как показано на странице MSDN, связанной ранее):

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

Ответ 4

У меня была такая же проблема при подключении к GitHub, которая требует агента пользователя. Таким образом, достаточно предоставить это, а не генерировать сертификат

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

Ответ 5

При подключении к https я тоже получил эту ошибку, я добавляю эту строку перед HttpClient httpClient = new HttpClient(); и успешно подключиться:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

Я знаю это из этого ответа и другого аналогичного ответа, а в комментарии упоминается:

Это полезный хакерский процесс в разработке, поэтому, если поместить вокруг него оператор #if DEBUG #endif, это как минимум то, что вам нужно сделать, чтобы сделать это безопаснее и остановить его в конечном итоге в производстве.

Кроме того, я не пробовал метод в другом ответе, который использует new X509Certificate() или new X509Certificate2() для создания сертификата, я не уверен, что просто создать с помощью new() будет работать или нет.

РЕДАКТИРОВАТЬ: Некоторые ссылки:

Создайте самоподписанный сертификат сервера в IIS 7

Импорт и экспорт SSL-сертификатов в IIS 7

Конвертировать .pfx в .cer

Лучшие практики для использования ServerCertificateValidationCallback

Я считаю, что значение Thumbprint равно x509certificate.GetCertHashString():

Получить отпечаток сертификата

Ответ 6

Просто указание HTTPS в URI должно сделать трюк.

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

Если запрос работает с HTTP, но не с HTTPS, то это, безусловно, проблема с сертификатом. Убедитесь, что вызывающий объект доверяет эмитенту сертификата и что сертификат не истек. Быстрый и простой способ проверить, что нужно сделать запрос в браузере.

Вы также можете проверить на сервере (если он ваш и/или если вы можете), что он настроен на правильное выполнение HTTPS-запросов.

Ответ 7

Я также получил ошибку:

Базовое соединение было закрыто: не удалось установить доверительные отношения для безопасного канала SSL/TLS.

... с приложением Xamarin Forms Android -targeting, пытающимся запросить ресурсы у поставщика API, для которого требуется TLS 1.3.

Решение состояло в том, чтобы обновить конфигурацию проекта для замены "управляемого" (.NET) http-клиента Xamarin (который не поддерживает TLS 1.3 с Xamarin Forms v2.5) и вместо этого использовать собственный клиент android.

Это простой проект переключения в визуальной студии. Смотрите скриншот ниже.

  • Свойства проекта
  • Настройки Android
  • продвинутый
  • Элемент списка
  • Измените "Реализация HttpClient" на "Android"
  • Измените реализацию SSL/TLS на "Собственный TLS 1. 2+"

enter image description here

Ответ 8

На уровне HttpClientHandler существует неглобальная настройка:

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

var client = new HttpClient(handler);

Таким образом, можно включить последние версии TLS.

Обратите внимание, что значением по умолчанию SslProtocols.Default на самом деле является SslProtocols.Ssl3 | SslProtocols.Tls (проверено на .Net Core 2.1 и .Net Framework 4.7.1).

Ответ 9

Вы можете попробовать использовать пакет Nuget ModernHttpClient: после загрузки пакета вы можете реализовать его следующим образом:

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


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

Ответ 10

Добавьте следующие объявления в ваш класс:

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

После:

var client = new HttpClient();

А также:

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

Счастливый? :)

Ответ 11

Я согласен с Felickz, но я также хочу добавить пример для разъяснения использования в С#. Я использую SSL в службе Windows следующим образом.

    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;

Если я собираюсь использовать его в веб-приложении, я просто изменяю реализацию на стороне прокси следующим образом:

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

Ответ 14

У меня была эта проблема, и в моем случае решение было глупо простым: открыть Visual Studio с правами администратора. Я попробовал все вышеупомянутые решения, и это не сработало, пока я не сделал это. Надеюсь, это сэкономит кому-то драгоценное время.

Ответ 15

Для ошибки:

Базовое соединение было закрыто: не удалось установить доверительные отношения для безопасного канала SSL/TLS.

Я думаю, что вам нужно безоговорочно принять сертификат со следующим кодом

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

Как написал Оппозиционный в своем ответе на вопрос .NET клиент подключается к ssl Web API.