Como faço para usar o WebRequest para acessar um site criptografado SSL usando https?

116

Estou escrevendo um programa que lê o conteúdo de um URL fornecido pelo usuário. Meu problema está no código mais ou menos assim:

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

E isso não funciona se o URL fornecido for um URL "https: //". Alguém pode me ajudar a mudar este código para que funcione com conteúdo criptografado SSL. Obrigado.

Alfred B. Thordarson
fonte

Respostas:

175

Você está fazendo isso da maneira correta, mas os usuários podem estar fornecendo urls para sites que possuem certificados SSL inválidos instalados. Você pode ignorar esses problemas de certificado se colocar esta linha antes de fazer a solicitação da web real:

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

onde AcceptAllCertificationsé definido 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
fonte
41
Obrigado por esta resposta! Para evitar algum código inútil, usei-o assim: ServicePointManager.ServerCertificateValidationCallback = (s, cert, chain, ssl) => true;
Charles Ouellet
4
Obrigado, você me ajudou senhor. F # torna isso muito mais fácil:ServicePointManager.ServerCertificateValidationCallback <- Security.RemoteCertificateValidationCallback (fun _ _ _ _ -> true)
David Grenier
2
@Charles Ouellet Acho que sou ainda mais preguiçoso do que você, (a, b, c, d) => true
Despertar
24
Eu prefiro+= delegate { return true; }
vkrzv
2
Esteja ciente dos riscos potenciais associados a esta abordagem. Consulte stackoverflow.com/a/6613434/2969615 para obter mais informações.
Joe Coyle
19

Este link é do seu interesse: http://msdn.microsoft.com/en-us/library/ds8bxk2a.aspx

Para conexões http, as classes WebRequest e WebResponse usam SSL para se comunicar com hosts da web que oferecem suporte a SSL. A decisão de usar SSL é feita pela classe WebRequest, com base no URI fornecido. Se o URI começar com "https:", o SSL será usado; se o URI começar com "http:", será usada uma conexão não criptografada.

GurdeepS
fonte
Ótimo link. Essa é uma distinção importante.
DanM7 de
1
Sua resposta implica que o código da pergunta deve funcionar?
Rowland Shaw
18

Este funcionou para mim:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Nani
fonte
1
O valor padrão é "Ssl2 | Tls". Eu tinha habilitado apenas Tls 1.1 e 1.2 em meu servidor. Isso realmente resolveu o problema! Para LetsEncrypt com nginX no linux, os protocolos são definidos aqui: /etc/letsencrypt/options-ssl-nginx.conf
Jerther
Acredito que se trate de uma questão diferente. Não se trata de certificados inválidos, mas de versões superiores de TLS.
wp78de
Eu estava recebendo "Uma conexão existente foi fechada à força pelo host remoto" e essa solução funcionou para mim
oamilkar
Observe que esta é uma configuração global, portanto, você só precisa fazer isso uma vez e não toda vez que configurar a solicitação.
Chad Hedgcock
Posso fazer isso para uma única solicitação de alguma forma? Parece que ServicePointManager é algo bastante global ...
wexman