Gunicorn: A configuração de criptografia SSL padrão desativa as criptografias mais seguras

Criado em 23 jan. 2019  ·  3Comentários  ·  Fonte: benoitc/gunicorn

O padrão para a opção --ciphers é TLSv1 .

Este valor é um padrão incorreto, porque desativa ativamente novas cifras fortes que estão disponíveis apenas com TLSv1.2. Em particular, não há interseção entre o conjunto de cifras configurado por este valor padrão e as cifras avaliadas A + pelo OWASP :

>>> import ssl
>>> ctx = ssl.SSLContext()
>>> ctx.set_ciphers('TLSv1')
>>> tlsv1 = {c['name'] for c in ctx.get_ciphers()}
>>> ctx.set_ciphers('DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256')  # From OWASP
>>> aplus = {c['name'] for c in ctx.get_ciphers()}
>>> aplus & tlsv1
set()

Isso pode levar a erros OpenSSL NO_SHARED_CIPHER para clientes configurados com configurações de alta segurança.

Uma solução seria simplesmente adicionar cifras TLSv1.2 ao conjunto, alterando o padrão para a string 'TLSv1:TLSv1.2' . Isso adicionaria compatibilidade para clientes configurados com configurações de segurança estritas, sem quebrar nenhum usuário existente do gunicorn. No entanto, isso deixaria cifras fracas no conjunto.

Uma opção mais segura seria escolher uma das strings OWASP como padrão, com base no nível de compatibilidade descrito. Por exemplo, OWASP Cipher String C ou C- preservaria a ampla compatibilidade enquanto descartava cifras conhecidas como fracas.

Em ambos os casos, a documentação pode ser atualizada para recomendar a substituição do padrão por um padrão mais forte com base no uso esperado, incluindo um link para a página OWASP como referência.

Feedback Requested FeaturSSL

Comentários muito úteis

Além disso, o Python tem sua própria lista de cifras padrão: nunca volta ao padrão do OpenSSL (que aparentemente é DEFAULT:!aNULL:!eNULL ). É acessível como ssl._DEFAULT_CIPHERS embora seja interno / não documentado, então a maneira de acessar os padrões é nunca chamar set_ciphers () em um SSLContext.

Para Python 3.6 _DEFAULT_CIPHERS é

'TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH:!aNULL:!eNULL:!MD5:!3DES'

No Python 3.7 é

'DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK'

com um comentário dizendo "DEFAULT: lista de cifras padrão do OpenSSL. Desde 1.0.2 a lista está em uma ordem razoável."

Essas configurações parecem ser bem justas e dentro do mesmo espírito do OWASP.

Há também um _RESTRICTED_SERVER_CIPHERS que se destina ao uso em servidores (tão perfeito para gunicorn) e é mais apertado do que _DEFAULT_CIPHERS em algumas versões de Python, mas isso é interno e não é usado em nenhum lugar - mas tem sido mantido desde pelo menos 3.4.

Portanto, a opção 3 é o padrão para o pacote de criptografia padrão do Python.

A única razão para não fazer isso é se pensarmos que poderíamos enviar uma lista hoje que seja mais segura do que nas versões anteriores do Python, ou que desejamos optar por um dos níveis OWASP ainda mais restritos. Honestamente, isso é muito marginal.

Todos 3 comentários

Obrigado por comunicar este problema. Estamos absolutamente cientes disso. Gunicorn não teve mudanças significativas em seu suporte SSL por um tempo. Veja # 1933 e os problemas vinculados a essa discussão.

Enquanto isso, se houver um padrão mais sensato agora que o Gunicorn só oferece suporte a Python 3.4+, envie uma solicitação de pull e terei prazer em mesclá-la. Também estamos considerando aumentar essa versão mínima, portanto, se houver uma versão mínima mais alta do Python que permitiria um padrão ainda mais seguro, poste essa informação aqui para ajudar a tomar essa decisão antes do próximo lançamento.

As cifras disponíveis (e a interpretação do argumento para SSLContext.set_ciphers() ) não são afetadas pela versão do Python, mas pela versão do OpenSSL / LibreSSL contra a qual o Python é construído. No Linux, essa normalmente seria a versão fornecida pela distro.

Se sua pergunta for "podemos definir um padrão mais seguro que sempre funcione no Python 3.4+", a resposta estrita é "não" porque depende de como você compilou o Python. Pode ser possível compilar um Python recente em um OpenSSL muito antigo que carece de cifras fortes, portanto, exigir cifras fortes no gunicorn pode significar que o SSL não funciona.

No entanto, acho que estamos bem seguros. O Python 3.4 foi lançado em 2014, enquanto o OpenSSL 1.0.1a, que adicionou o TLSv1.2, foi lançado em abril de 2012. Portanto, as versões distro do Python provavelmente terão cifras fortes. A outra coisa é que cada versão do Python requer uma determinada versão do OpenSSL (por exemplo, o Python 3.7 requer o OpenSSL 1.0.2, eu entendo), mas não sei exatamente quais versões do Python exigem o quê.

No geral, eu teria que ser orientado pelo OWASP. Eles dizem que C- é "Legado, a mais ampla compatibilidade com navegadores antigos e bibliotecas legadas" - com a vantagem adicional de poderem ser citados como a fonte.

Além disso, o Python tem sua própria lista de cifras padrão: nunca volta ao padrão do OpenSSL (que aparentemente é DEFAULT:!aNULL:!eNULL ). É acessível como ssl._DEFAULT_CIPHERS embora seja interno / não documentado, então a maneira de acessar os padrões é nunca chamar set_ciphers () em um SSLContext.

Para Python 3.6 _DEFAULT_CIPHERS é

'TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH:!aNULL:!eNULL:!MD5:!3DES'

No Python 3.7 é

'DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK'

com um comentário dizendo "DEFAULT: lista de cifras padrão do OpenSSL. Desde 1.0.2 a lista está em uma ordem razoável."

Essas configurações parecem ser bem justas e dentro do mesmo espírito do OWASP.

Há também um _RESTRICTED_SERVER_CIPHERS que se destina ao uso em servidores (tão perfeito para gunicorn) e é mais apertado do que _DEFAULT_CIPHERS em algumas versões de Python, mas isso é interno e não é usado em nenhum lugar - mas tem sido mantido desde pelo menos 3.4.

Portanto, a opção 3 é o padrão para o pacote de criptografia padrão do Python.

A única razão para não fazer isso é se pensarmos que poderíamos enviar uma lista hoje que seja mais segura do que nas versões anteriores do Python, ou que desejamos optar por um dos níveis OWASP ainda mais restritos. Honestamente, isso é muito marginal.

Esta página foi útil?
0 / 5 - 0 avaliações