Как использовать WebRequest для доступа к сайту с шифрованием SSL с помощью https?

116

Я пишу программу, которая читает контент с предоставленного пользователем URL. Моя проблема в коде, который выглядит примерно так:

Uri uri = new Uri(url);
WebRequest webRequest = WebRequest.Create(uri);
WebResponse webResponse = webRequest.GetResponse();
ReadFrom(webResponse.GetResponseStream());

И это нарушает, если предоставленный URL-адрес является URL-адресом "https: //". Может ли кто-нибудь помочь мне изменить этот код, чтобы он работал с зашифрованным контентом SSL. Спасибо.

Альфред Б. Тордарсон
источник

Ответы:

175

Вы делаете это правильно, но пользователи могут предоставлять URL-адреса сайтов, на которых установлены недействительные сертификаты SSL. Вы можете игнорировать эти проблемы с сертификатом, если вы введете эту строку до того, как сделаете фактический веб-запрос:

ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(AcceptAllCertifications);

где AcceptAllCertificationsопределяется как

public bool AcceptAllCertifications(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certification, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
    return true;
}
Люк Дафф
источник
41
Спасибо за этот ответ! Чтобы избежать бесполезного кода, я использовал его так: ServicePointManager.ServerCertificateValidationCallback = (s, cert, chain, ssl) => true;
Charles Ouellet
4
Спасибо, вы мне помогли, сэр. F # делает это намного проще:ServicePointManager.ServerCertificateValidationCallback <- Security.RemoteCertificateValidationCallback (fun _ _ _ _ -> true)
Дэвид Гренье,
2
@Charles Ouellet, я думаю, я даже ленив, чем вы, (a, b, c, d) => true
Despertar
24
Я предпочитаю+= delegate { return true; }
vkrzv
2
Помните о потенциальных рисках, связанных с этим подходом. См. Stackoverflow.com/a/6613434/2969615 для получения дополнительной информации.
Джо Койл,
19

Вам будет интересна эта ссылка: http://msdn.microsoft.com/en-us/library/ds8bxk2a.aspx

Для HTTP-соединений классы WebRequest и WebResponse используют SSL для связи с веб-узлами, поддерживающими SSL. Решение об использовании SSL принимает класс WebRequest на основе предоставленного ему URI. Если URI начинается с «https:», используется SSL; если URI начинается с «http:», используется незашифрованное соединение.

GurdeepS
источник
Отличная ссылка. Это важное различие.
DanM7
1
Ваш ответ подразумевает, что код в вопросе должен работать?
Роуленд Шоу,
18

Это сработало для меня:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Нани
источник
1
Значение по умолчанию - «Ssl2 | Tls». У меня на сервере были только Tls 1.1 и 1.2. Это действительно устранило проблему! Для LetsEncrypt с nginX в Linux протоколы определены здесь: /etc/letsencrypt/options-ssl-nginx.conf
Джертер
Я считаю, что это другой вопрос. Речь идет не о недействительных сертификатах, а о более высоких версиях TLS.
wp78de
Я получал сообщение «Существующее соединение было принудительно закрыто удаленным хостом», и это решение сработало для меня
oamilkar
Обратите внимание, что это глобальная конфигурация, поэтому вам нужно делать это только один раз, а не каждый раз, когда вы настраиваете запрос.
Чад Хеджкок
Могу я как-нибудь сделать это для одного запроса? Похоже, ServicePointManager - это довольно глобальная вещь ...
wexman