Erros de SSL/TLS em navegadores muito antigos conectando ao Discourse

Após configurar minha instância do Discourse com o suporte padrão do Let’s Encrypt, recebi relatos de alguns usuários de que seus navegadores não conseguem estabelecer uma conexão segura com o Discourse. Um print de tela que obtive de um usuário aponta claramente para um erro de SSL/TLS. É um erro do lado do navegador, e os usuários nem sequer veem qualquer coisa do Discourse.

Pelo contexto, parece que esses usuários têm sistemas operacionais ou navegadores um pouco mais antigos. Suspeitei inicialmente que o suporte a TLS 1.2 fosse o problema, mas o usuário com quem verifiquei está usando o Safari 10.1.2 no macOS (versão desconhecida) e, de acordo com Can I use... Support tables for HTML5, CSS3, etc, o Safari deve suportar TLS 1.2 desde a versão 7.

Existe outra razão, além do TLS 1.2, que faria um navegador ou sistema operacional falhar ao tentar estabelecer uma conexão segura com uma instalação padrão do Discourse usando o suporte padrão a TLS via Let’s Encrypt? Estou tentando descobrir quais perguntas devo fazer aos meus usuários para identificar qual é o problema e em qual extremidade ele deve ser corrigido.

Como solução alternativa: Pelo que pude ver, o padrão é redirecionar o tráfego que vai para http para https. Existe alguma maneira de fazer uma verificação primeiro, algo como “apenas se o navegador suportar TLS 1.2” ou “apenas se o navegador/SO for de uma versão superior”, caso contrário, manter o http?

Aqui está a URL, caso você tenha alguma ideia de como verificar se algo está configurado incorretamente: https://forum.stadtteilgenossenschaft-wik.de

Você pode testar seu site usando o SSL Server Test. Os resultados do teste contêm uma seção chamada “Simulação de Handshake”, que deve mostrar as combinações de navegador/SO que funcionam ou não.

Com a imagem Docker mais recente, estou vendo a seguinte configuração TLS:

Você pode enviar seus usuários para https://www.ssllabs.com/ssltest/viewMyClient.html para obter mais informações sobre suas versões de navegador e SO, bem como as versões de TLS suportadas.

Obrigado pela resposta detalhada!

Executei o SSL Server Test e não consegui encontrar nada de errado no resultado:

Eles são os mesmos que os do seu post, pelo que pude ver.

As únicas falhas foram para versões antigas de OS + Safari (Safari 8+9) e versões antigas do Windows com IE 11. Essa última me preocupa um pouco: o IE 11 não deveria ser compatível com o Discourse e também suportar TLS 1.2 por padrão?

O teste também não inclui uma verificação para o Safari 10 no sistema operacional mais antigo ainda suportado, então talvez isso também falhe…

Para os usuários em versões antigas do Windows, você provavelmente precisará habilitar as cifras CBC:

A próxima coisa que você deve fazer é enviar esses usuários para

para obter informações sobre o que o navegador deles suporta. A maneira mais fácil de compartilhar o resultado deles é provavelmente pedindo para imprimirem em PDF e enviarem para você.

Obrigado, recebi uma resposta do meu usuário. Ele está usando um iPod Touch muito antigo:

Capacidades SSL/TLS do seu navegador
Agente de usuário: Mozilla/5.0 (iPod; CPU iPhone OS 6_1_6 como Mac OS X) AppleWebKit/536.26 (KHTML, como Gecko) Versão/6.0 Mobile/10B500 Safari/8536.25

Suporte a protocolos

Seu agente de usuário tem bom suporte a protocolos.

Seu agente de usuário suporta TLS 1.2, que é a versão de protocolo recomendada no momento.

Então, embora seja antigo (e eu saiba que está muito longe do sistema operacional + navegador mínimo suportado pelo Discourse), gostaria de permitir que ele, pelo menos, se conecte ao site e veja como seu navegador lida com o HTML e JavaScript modernos.

Este é o relatório detalhado de suporte TLS:

Recursos do protocolo

Protocolos

TLS 1.3 Não
TLS 1.2 Sim
TLS 1.1 Sim
TLS 1.0 Sim
SSL 3 Sim
SSL 2 Não

Conjuntos de cifras (em ordem de preferência)

TLS_EMPTY_RENEGOTIATION_INFO_SCSV ( 0xff ) -
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 ( 0xc024 ) FRACO 256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 ( 0xc023 ) FRACO 128
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA ( 0xc00a ) FRACO 256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA ( 0xc009 ) FRACO 128
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA ( 0xc007 ) INSEGURO 128
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA ( 0xc008 ) FRACO 112
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 ( 0xc028 ) FRACO 256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 ( 0xc027 ) FRACO 128
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA ( 0xc014 ) FRACO 256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA ( 0xc013 ) FRACO 128
TLS_ECDHE_RSA_WITH_RC4_128_SHA ( 0xc011 ) INSEGURO 128
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA ( 0xc012 ) FRACO 112
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 ( 0xc026 ) FRACO 256
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 ( 0xc025 ) FRACO 128
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 ( 0xc02a ) FRACO 256
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 ( 0xc029 ) FRACO 128
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA ( 0xc004 ) FRACO 128
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA ( 0xc005 ) FRACO 256
TLS_ECDH_ECDSA_WITH_RC4_128_SHA ( 0xc002 ) INSEGURO 128
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA ( 0xc003 ) FRACO 112
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA ( 0xc00e ) FRACO 128
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA ( 0xc00f ) FRACO 256
TLS_ECDH_RSA_WITH_RC4_128_SHA ( 0xc00c ) INSEGURO 128
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA ( 0xc00d ) FRACO 112
TLS_RSA_WITH_AES_256_CBC_SHA256 ( 0x3d ) FRACO 256
TLS_RSA_WITH_AES_128_CBC_SHA256 ( 0x3c ) FRACO 128
TLS_RSA_WITH_AES_128_CBC_SHA ( 0x2f ) FRACO 128
TLS_RSA_WITH_RC4_128_SHA ( 0x5 ) INSEGURO 128
TLS_RSA_WITH_RC4_128_MD5 ( 0x4 ) INSEGURO 128
TLS_RSA_WITH_AES_256_CBC_SHA ( 0x35 ) FRACO 256
TLS_RSA_WITH_3DES_EDE_CBC_SHA ( 0xa ) FRACO 112
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 ( 0x67 ) FRACO 128
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 ( 0x6b ) FRACO 256
TLS_DHE_RSA_WITH_AES_128_CBC_SHA ( 0x33 ) FRACO 128
TLS_DHE_RSA_WITH_AES_256_CBC_SHA ( 0x39 ) FRACO 256
TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA ( 0x16 ) FRACO 112
TLS_ECDHE_ECDSA_WITH_NULL_SHA ( 0xc006 ) INSEGURO 0
TLS_ECDHE_RSA_WITH_NULL_SHA ( 0xc010 ) INSEGURO 0
TLS_ECDH_ECDSA_WITH_NULL_SHA ( 0xc001 ) INSEGURO 0
TLS_ECDH_RSA_WITH_NULL_SHA ( 0xc00b ) INSEGURO 0
TLS_RSA_WITH_NULL_SHA256 ( 0x3b ) INSEGURO 0
TLS_RSA_WITH_NULL_SHA ( 0x2 ) INSEGURO 0
TLS_RSA_WITH_NULL_MD5 ( 0x1 ) INSEGURO 0
(1) Quando um navegador suporta SSL 2, seus conjuntos de cifras exclusivos do SSL 2 são mostrados apenas na primeira conexão com este site. Para ver os conjuntos, feche todas as janelas do navegador e, em seguida, abra esta página exata diretamente. Não atualize.

Detalhes do protocolo

Indicação de nome de servidor (SNI) Sim
Renegociação segura Sim
Compressão TLS Não
Tickets de sessão Não
Stapling OCSP Não
Algoritmos de assinatura SHA384/RSA, SHA256/RSA, SHA1/RSA, SHA256/ECDSA, SHA1/ECDSA
Grupos nomeados secp256r1, secp384r1, secp521r1
Negociação do próximo protocolo Não
Negociação de protocolo da camada de aplicação Não
Compatibilidade de handshake SSL 2 Não

Tratamento de conteúdo misto

Testes de conteúdo misto
Imagens Passivo Sim
CSS Ativo Sim
Scripts Ativo Sim
XMLHttpRequest Ativo Sim
WebSockets Ativo Sim
Frames Ativo Sim
(1) Esses testes podem causar um aviso de conteúdo misto no seu navegador. Isso é esperado.
(2) Se você vir um teste falho, tente recarregar a página. Se o erro persistir, entre em contato.

Desculpe pela formatação; o usuário copiou e colou o HTML de texto rico para mim e parte dele se perde ao colar no Discourse. Vou tentar descobrir como corrigir a formatação mais tarde.

Como disse, gostaria de permitir que ele, pelo menos, estabeleça uma conexão segura para que ele veja algo, e isso deve ser possível, já que o navegador suporta TLS 1.2. Mas acho que teria que habilitar alguma configuração menos segura para TLS 1.2 para que o navegador dele seja suportado. Não sei o suficiente sobre TLS para correlacionar a saída desse relatório com o que o servidor suporta e o que eu teria que mudar. Você pode me dizer o que está faltando e o que eu teria que mudar?

Tenho uma ideia vaga do que você quer dizer, mas não faço ideia de como fazer isso. Você pode me indicar alguma documentação que explique como alterar a configuração TLS do contêiner Docker do Discourse para habilitar essas cifras?

Acho que o Safari 6 não funcionará, mesmo que você resolva os problemas de TLS adicionando suites de cifra adicionais.

Você pode adicionar suites de cifra ausentes sobrescrevendo o arquivo de configuração do nginx. Adicione o seguinte trecho (não testado, mas deve funcionar) à seção hooks do app.yml e altere o valor de ssl_ciphers conforme desejar.

  after_ssl:
    - replace:
        filename: "/etc/nginx/conf.d/discourse.conf"
        from: /ssl_ciphers .*/
        to: ssl_ciphers <sua_lista_completa_de_cifras>;

Aliás: estou tentando adicionar suporte a certificados de Curva Elíptica ao Discourse, o que permitiria que ele funcionasse com o IE11 sem necessidade de configurações extras.

iOS 6?! A última versão foi lançada no início de 2014! Isso foi há mais de 5 anos!

Eu sei, fiquei tão surpreso quanto você. Não espero que você o suporte, mas gostaria que o usuário recebesse pelo menos algum HTML e visse o que funciona e o que não funciona.

Obrigado, @gerhard. Fiz a alteração que você descreveu no /var/discourse/containers/app.yml (espero que fosse o arquivo app.yml correto) e, em seguida, executei /var/discourse/launcher rebuild app, conforme descrito nos comentários do app.yml.

Depois, executei novamente o teste no ssllabs.com, mas parece que o resultado não mudou: https://www.ssllabs.com/ssltest/analyze.html?d=forum.stadtteilgenossenschaft-wik.de&s=68.183.214.228&hideResults=on

Não tenho certeza de como verificar se a alteração de configuração realmente funcionou (mas não influenciou o resultado do teste) ou se a alteração de configuração não funcionou.

Ah, eu não li seu post direito, @gerhard. Se eu entendi corretamente, a configuração que você forneceu tornará os cifras utilizados explícitos, mas o valor que você usou é basicamente o mesmo que o padrão, certo? Então, eu ainda teria que expandi-la com outras cifras que possam ser suportadas por navegadores mais antigos.

Sim, exatamente. Eu não queria postar uma solução para adicionar cifras fracas na configuração. Você terá que resolver isso por conta própria. :wink:

Mas, se você estiver fazendo essas alterações, fique de olho no pull request que mencionei anteriormente. Se ele for mesclado, o IE11 funcionará imediatamente.

Entendo, você não quer facilitar demais para que alguém configure seu ambiente de forma insegura. Respeito isso e também não vou postar o código completo.

Aqui está o que consegui até agora: identifiquei os suites de cifra ausentes para dar suporte a navegadores e sistemas operacionais mais antigos, consultando, por exemplo, Qualys SSL Labs - Projects / User Agent Capabilities: Safari 6 / iOS 6.0.1 (e outros também). Como as suites de cifra do cliente são listadas por preferência, sempre escolhi a primeira da lista e garanti que estivesse sendo suportada, assumindo que, se o servidor suportar pelo menos uma da lista, isso seria suficiente. Aqui estão as cifras que identifiquei:

  • ECDHE-ECDSA-AES256-CBC-SHA384 para Safari 6–8
  • ECDHE-RSA-AES256-CBC-SHA384 para IE 11 no Windows 7/8.1/Phone 8.1 Update (segundo @supermathie)
  • ECDHE-RSA-AES128-CBC-SHA256 para IE 11 no Windows Phone 8.1

Adicionei esses valores ao final da lista de ssl_ciphers, separados por dois-pontos, assumindo que “final da lista” significa “menos preferido, será usado apenas se o cliente não suportar nada mais”. Em seguida, executei /var/discourse/launcher rebuild app para aplicar a nova configuração e refiz o teste em SSL Server Test (Powered by Qualys SSL Labs) após limpar o cache. Mas os resultados não mudaram.

Eu esperava que agora funcionasse tanto para os testes com falha no IE 11 quanto para o Safari 6–8, mas o handshake ainda falha. Então, devo estar perdendo algo.

Além disso, um dos meus usuários está usando um iPhone com iOS 9/Safari 9 e, para ele, a conexão também falha. Mas, de acordo com os resultados do teste do SSL Labs, essa conexão já deveria funcionar nativamente (como também é visível no resultado de @gerhard acima).

Então, devo estar perdendo duas coisas:

  1. Por que a conexão ainda não está funcionando após adicionar suporte às cifras?
  2. Por que o SSLLabs diz que funciona para iOS 9 + Safari 9, mas na prática não funciona para meu usuário?

Quanto ao ponto 1: ainda não tenho certeza se apliquei a configuração corretamente. Além do teste do SSL Labs, existe outra maneira de verificar quais cifras o servidor suporta para confirmar se minha alteração de configuração foi realmente aplicada corretamente?

Depois de analisar mais de perto o resultado do SSLLab, acho que isso não funcionou.

Este é o resultado que vejo no SSLLabs para meu servidor após aplicar a configuração e reconstruir:

Pelo que entendo, deveria listar muitos mais, já que a configuração possui muitas outras opções. Isso significa que essa alteração na configuração não funcionou?

Acho que os nomes dos cifras que você escolheu estão incorretos. Mapping OpenSSL cipher suite names to IANA names é um bom recurso para mapear entre as cifras listadas no SSL Server Test e os nomes usados pelo OpenSSL (nginx).

Nos meus testes, adicionei :ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA e, após uma nova compilação, o teste ficou assim:

Talvez haja um bug no teste? :man_shrugging: Não tenho um Safari tão antigo para testar. Nós suportamos apenas o Safari 10+. Tem certeza de que ainda falha devido a um erro de TLS?

Obrigado, vou tentar isso!

Eu examinei um pouco mais os arquivos de configuração do Discourse e encontrei templates/web.ssl.template.yml. Qual é a diferença entre fazer essa alteração nos ciphers através do arquivo app.yml e apenas alterar a lista de ssl_ciphers diretamente em templates/web.ssl.template.yml?

O template está sob controle de versão e o app.yml não. Você terá problemas ao atualizar o repositório se editar o template.

Obrigado, esse era o problema e corrigir os nomes fez o handshake funcionar para todos os navegadores testados na lista do SSLLabs. Muito obrigado pela sua paciência!

Agora, estou interessado em saber o que meus usuários estão vendo depois que passaram pelo erro HTTPS com seus navegadores antigos. :smiley: