Jak używać WebRequest, aby uzyskać dostęp do witryny zaszyfrowanej za pomocą protokołu SSL przy użyciu protokołu HTTPS?

116

Piszę program, który czyta zawartość z adresu URL podanego przez użytkownika. Mój problem tkwi w kodzie, który wygląda mniej więcej tak:

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

I to jest złe, jeśli podany adres URL jest adresem URL „https: //”. Czy ktoś może mi pomóc w zmianie tego kodu tak, aby działał z treścią zaszyfrowaną SSL. Dzięki.

Alfred B. Thordarson
źródło

Odpowiedzi:

175

Robisz to we właściwy sposób, ale użytkownicy mogą podawać adresy URL witryn, które mają zainstalowane nieprawidłowe certyfikaty SSL. Możesz zignorować te problemy z certyfikatami, jeśli umieścisz tę linię przed wysłaniem rzeczywistego żądania internetowego:

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

gdzie AcceptAllCertificationsjest zdefiniowany jako

public bool AcceptAllCertifications(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certification, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
    return true;
}
LukeDuff
źródło
41
Dzięki za tę odpowiedź! Aby uniknąć niepotrzebnego kodu, użyłem go w ten sposób: ServicePointManager.ServerCertificateValidationCallback = (s, cert, chain, ssl) => true;
Charles Ouellet
4
Dzięki, pomogłeś mi, sir. F # to bardzo ułatwia:ServicePointManager.ServerCertificateValidationCallback <- Security.RemoteCertificateValidationCallback (fun _ _ _ _ -> true)
David Grenier
2
@Charles Ouellet Myślę, że jestem jeszcze bardziej leniwy niż ty, (a, b, c, d) => prawda
Despertar,
24
Wolę+= delegate { return true; }
vkrzv
2
Miej świadomość potencjalnych zagrożeń związanych z tym podejściem. Więcej informacji można znaleźć pod adresem stackoverflow.com/a/6613434/2969615 .
Joe Coyle
19

To łącze Cię zainteresuje: http://msdn.microsoft.com/en-us/library/ds8bxk2a.aspx

W przypadku połączeń http klasy WebRequest i WebResponse używają protokołu SSL do komunikacji z hostami internetowymi obsługującymi protokół SSL. Decyzja o użyciu SSL jest podejmowana przez klasę WebRequest na podstawie nadanego URI. Jeśli identyfikator URI zaczyna się od „https:”, używany jest protokół SSL; jeśli identyfikator URI zaczyna się od „http:”, używane jest połączenie niezaszyfrowane.

GurdeepS
źródło
Świetny link. To ważna różnica.
DanM7,
1
Twoja odpowiedź sugeruje, że kod w pytaniu powinien działać?
Rowland Shaw
18

Ten pracował dla mnie:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Nani
źródło
1
Wartość domyślna to „Ssl2 | Tls”. Miałem tylko włączone Tls 1.1 i 1.2 na moim serwerze. To rzeczywiście rozwiązało problem! Dla LetsEncrypt with nginX w systemie Linux protokoły są zdefiniowane tutaj: /etc/letsencrypt/options-ssl-nginx.conf
Jerther
Uważam, że dotyczy to innej kwestii. Nie chodzi o nieprawidłowe certyfikaty, ale o wyższe wersje TLS.
wp78de
Otrzymywałem informację
Zauważ, że jest to konfiguracja globalna, więc musisz to zrobić tylko raz, a nie za każdym razem, gdy konfigurujesz żądanie.
Chad Hedgcock
Czy mogę to jakoś zrobić dla jednej prośby? Wygląda na to, że ServicePointManager jest raczej globalną rzeczą ...
wexman