¿Cómo utilizo WebRequest para acceder a un sitio encriptado SSL usando https?

116

Estoy escribiendo un programa que lee contenido de una URL proporcionada por el usuario. Mi problema está en el código que dice algo como esto:

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

Y esto se rompe si la URL proporcionada es una URL "https: //". ¿Alguien puede ayudarme a cambiar este código para que funcione con contenido cifrado SSL? Gracias.

Alfred B. Thordarson
fuente

Respuestas:

175

Lo está haciendo de la manera correcta, pero los usuarios pueden estar proporcionando URL a sitios que tienen instalados certificados SSL no válidos. Puede ignorar esos problemas de certificado si coloca esta línea antes de realizar la solicitud web real:

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

donde AcceptAllCertificationsse define como

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
fuente
41
¡Gracias por esta respuesta! Para evitar algunos códigos inútiles, lo usé así: ServicePointManager.ServerCertificateValidationCallback = (s, cert, chain, ssl) => true;
Charles Ouellet
4
Gracias, me ayudó señor. F # hace que esto sea más fácil:ServicePointManager.ServerCertificateValidationCallback <- Security.RemoteCertificateValidationCallback (fun _ _ _ _ -> true)
David Grenier
2
@Charles Ouellet Supongo que soy incluso más vago que tú, (a, b, c, d) => cierto
Despertar
24
Prefiero+= delegate { return true; }
vkrzv
2
Sea consciente de los riesgos potenciales asociados con este enfoque. Consulte stackoverflow.com/a/6613434/2969615 para obtener más información.
Joe Coyle
19

Este enlace será de su interés: http://msdn.microsoft.com/en-us/library/ds8bxk2a.aspx

Para las conexiones http, las clases WebRequest y WebResponse utilizan SSL para comunicarse con los servidores web que admiten SSL. La decisión de utilizar SSL la toma la clase WebRequest, en función del URI que se proporciona. Si el URI comienza con "https:", se utiliza SSL; si el URI comienza con "http:", se utiliza una conexión no cifrada.

GurdeepS
fuente
Gran enlace. Esa es una distinción importante.
DanM7
1
¿Su respuesta implica que el código de la pregunta debería funcionar?
Rowland Shaw
18

Este funcionó para mí:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Nani
fuente
1
El valor predeterminado es "Ssl2 | Tls". Solo había habilitado Tls 1.1 y 1.2 en mi servidor. ¡Esto realmente solucionó el problema! Para LetsEncrypt con nginX en Linux, los protocolos se definen aquí: /etc/letsencrypt/options-ssl-nginx.conf
Jerther
Creo que se trata de un tema diferente. No se trata de certificados no válidos, sino de versiones TLS superiores.
wp78de
Estaba obteniendo "Una conexión existente fue cerrada por la fuerza por el host remoto" y esta solución funcionó para mí
oamilkar
Tenga en cuenta que esta es una configuración global, por lo que solo tiene que hacer esto una vez y no cada vez que configure la solicitud.
Chad Hedgcock
¿Puedo hacer esto para una sola solicitud de alguna manera? Parece que ServicePointManager es algo bastante global ...
wexman