.NET - TLS, SSL - Solving Problems

Transport Layer Security (TLS) já é amplamente utilizada como uma opção mais avançada ao Secure Sockets Layer (SSL), por fim a função de ambas é a mesma e a troca do nome se deve a uma questão "comercial" - digamos assim. O HTTPS é uma implementação do TLS quando falamos em segurança de comunicação criptografada entre aplicações web e servidores. O servidor deve ter um certificado TLS instalado, comumente chamado de SSL certificate.

Versions

Temos 3 (três) versões do SSL:

  • SSL 1.0 – não entrou em operação por a questões de segurança não resolvidas;
  • SSL 2.0 – se tornou deprecated em 2011 por questões de segurança e a recomendação foi usar o TLS 1.2 ou superior;
  • SSL 3.0 – se tornou deprecated em 2015 por questões de segurança.

Temos 4 (quatro) vesões do TLS:

  • 1.0: É uma atualização do SSL 3.0, se tornará deprecated em 2020;
  • 1.1: Se tornará deprecated em 2020;
  • 1.2: Lançado em 2008 e ainda em operação;
  • 1.3: Esta é a versão mais recente, definida em 2018 através da RFC 8446.

A versão 1.0 era a antiga versão 3.1 do SSL.

How does TLS work

Não entrarei em muitos detalhes aqui, mas se você utiliza ferramentas como o Fiddler, você vai perceber no Response da Request que estará presente o handshake ClientHello, pode parecer estranho em um primeiro momento, mas é desta forma que o browser recebe um ok do servidor, enquanto isso essa troca se torna verdadeira por conta da segurança aplicada que comumente não enxergamos da implementação do protocolo.

Problems

Algumas empresas tem feito atualizações do TLS em seus servidores, inclusive a própria Microsoft através de sua núvem Azure e estas atualizações tem impactado as aplicações com alguns erros que tem ocorrido.

Há situações em que a empresa desabilita tais protocolos no servidor, contribuindo para o aparecimento de problemas

A mensagem de erro a seguir é bem genérica, ocorre em diversas situações, até mesmo com conexões realizadas ao banco de dados SQL Server.

An existing connection was forcibly closed by the remote host

The request was aborted: Could not create SSL/TLS secure channel

Veja este caso, divulgado pela Microsoft em 2020 sobre esta mudança para quem utiliza o SDK .NET Framework para comunicação com a API do PowerBI.
Atualize a versão TLS do seu aplicativo do Power BI para TLS 1.2

Mas, uma das possíveis causas é a aualização do TLS no servidor, uma simples mudança da versão 1.1 para a 1.2 já pode gerar transtornos nas aplicações que usam .NET Framework 4.6.x.

.NET

Neste artigo TLS 1.2 and .NET Support: How to Avoid Connection Errors, está bem explicado as diferenças de uso do .NET Framework e como cada uma das versões permite habilitar o uso do TLS em uma determinada versão.
Tenho uma observação sobre este artigo, que o .NET Framework 4.6.1 não tem TLS 1.2 habilitado por padrão. Para mais informações pode conferir no próprio site da Microsoft sobre o assunto: How to enable TLS 1.2

Portanto, antes de mudar a configuração do servidor, pensando em trazer melhorias na segurança, verifique se suas aplicações .NET suportam esta mudança. Na GRANDE maioria dos casos a mudança de versão do .NET Framework é traumática por conta da forma com que foram construídas, tais mudanças fazem com que o software não funcione mais, ou cause incompatibilidades tornando a migração dura e dolorida.

Temos o costume de olhar a tela de erro onde tem o StackTrace completo e vendo somente as primeiros duas ou três linhas, que são as últimas execuções, mas vale reforçar aqui que no meio de toda aquela mensagem pode ter um trecho como o mostrado a seguir, este é a grande pista de que o problema está relacionado a incompatibilidade do TLS entre o servidor e a aplicação.

System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result)  

A seguir o StackTrace completo.

[SocketException (0x2746): An existing connection was forcibly closed by the remote host]
   System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size) +226
[IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.]
   System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size) +811
   System.Net.FixedSizeReader.ReadPacket(Byte[] buffer, Int32 offset, Int32 count) +48
   System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest) +228
   System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest) +361
   System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest) +207
   System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult) +806
   System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) +370
   System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) +21
   System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) +85
   System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result) +1131
   System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size) +62
   System.Net.PooledStream.Write(Byte[] buffer, Int32 offset, Int32 size) +124
   System.Net.ConnectStream.WriteHeaders(Boolean async) +491
[WebException: The underlying connection was closed: An unexpected error occurred on a send.]
   System.Net.HttpWebRequest.GetResponse() +1751
   Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync(RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext) 

Browsers

Como o TLS é um protocolo de segurança no tráfego de informações entre o cliente e o servidor, podemos dizer que o browser (navegador) ter influência e responsabilidade direta neste processo, mas algumas versões ainda possuem limitações conforme os links a seguir:

Windows Server Registry Configuration

Através do Registry Editor, você pode habilitar ou desabilitar os protocolos, SSL e TLS e suas respectivas versões seguindo os passos abaixo onde a imagem é uma parte da configuração completa a título de exemplo.

  1. Caminho: Computer\HKEYLOCALMACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols

  2. Na pasta "Protocolos", crie as pastas (botão direito New > Key) para:
    SSL 2.0
    SSL 3.0
    TLS 1.0
    TLS 1.1
    TLS 1.2
    TLS 1.3

  3. Em cada uma das pastas de cada protocolo, crie outras 2 pastas:
    Client
    Server

  4. Para cada Client, crie um novo valor botão direito "New > DWORD (32 bits) Value"

  5. Sugiro o nome "DisabledByDefault".

SSL TLS Client Configuration

  1. Para habilitar o protocolo, altere o valor "0" e escolha a opção "Hexadecimal".

  2. Para desabilitar o protocolo, altere o valor "1" e escolha a opção "Hexadecimal".

  3. Para cada Server, crie um novo valor botão direito "New > DWORD (32 bits) Value"

  4. Sugiro o nome "Enabled".

SSL TLS Server Configuration

  1. Para habilitar o protocolo, altere o valor "1" e escolha a opção "Hexadecimal".

  2. Para desabilitar o protocolo, altere o valor "0" e escolha a opção "Hexadecimal".

O Client e o Server tem valores invertidos para habilitar e desabilitar

Realize os passos 1 ao 10 para todos os protocolos.

Solutions

Formas de solucionar o problema, cada ponto abaixo pode ser adotado de forma independente, não precisa usar todos para solucionar o problema.

<system.web>  
  <compilation debug="true" targetFramework="4.6" />
  <httpRuntime targetFramework="4.6.2" />
</system.web>  

O motivo do elemento targetFramework existir é para manter a compatibilidade entre diferentes versões do framework, uma de compilação e outra de execução, que podem ser diferentes.

O elemento compilation indica que o projeto foi desenvolvido ou recebeu atualização para a versão 4.6, enquanto a configuração httpRuntime vai manter a compatibilidade durante a execução. Portanto, para os casos de precisar habilitar o TLS 1.2 por exemplo, você não precisaria mudar toda a compilação do projeto, bastaria apenas alterar o targetFramework para versão 4.6.2.

  • Incluir no Global.asax.cs na inicialização da aplicação o código a seguir
public class Global : System.Web.HttpApplication  
{
    void Application_Start(object sender, EventArgs e)
    {
        ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
    }
}
  • Atualizar o .NET Framework de sua aplicação para a versão 4.6.2 ou superior, esta opção pode ser bem dolorosa, mas cabe aqui uma reflexão caso seja uma dor para você.

Repense a forma com que a arquitetura do seu sistema, seja um monolito ou não, foi pensada, idealizada e projetada para que uma atualização do .NET Framework não seja um Épico sem fim