Gunicorn: 默认 SSL 密码设置禁用最安全的密码

创建于 2019-01-23  ·  3评论  ·  资料来源: benoitc/gunicorn

--ciphers选项的默认值是TLSv1

此值是一个糟糕的默认值,因为它会主动禁用仅适用于 TLSv1.2 的新的强密码。 特别是,此默认值配置的密码集与OWASP 评级为 A+ 的密码之间没有交集:

>>> 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()

对于配置了高安全性设置的客户端,这可能会导致 OpenSSL NO_SHARED_CIPHER错误。

一种解决方案是简单地将 TLSv1.2 密码添加到集合中,方法是将默认值更改为字符串'TLSv1:TLSv1.2' 。 这将为配置了严格安全设置的客户端增加兼容性,而不会破坏任何现有的 gunicorn 用户。 但是,这会在集合中留下弱密码。

更安全的选择是根据描述的兼容性级别选择OWASP 字符串之一作为默认值。 例如,OWASP Cipher String C 或 C- 将保持广泛的兼容性,同时排除已知的弱密码。

在任何一种情况下,都可以更新文档以建议根据预期使用情况用更强的默认值替换默认值,包括指向 OWASP 页面的链接作为参考。

Feedback Requested FeaturSSL

最有用的评论

此外,Python 有自己的默认密码列表:它永远不会回退到 OpenSSL 的默认值(显然是DEFAULT:!aNULL:!eNULL )。 它可以作为ssl._DEFAULT_CIPHERS访问,尽管这是内部/未记录的,因此访问默认值的方法是永远不要在 SSLContext 上调用 set_ciphers()。

对于 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'

在 Python 3.7 中它是

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

一条评论说“默认:OpenSSL 的默认密码列表。从 1.0.2 开始,列表的顺序是合理的。”

这些设置似乎非常紧凑,并且与 OWASP 具有相同的精神。

还有一个_RESTRICTED_SERVER_CIPHERS用于服务器(非常适合 gunicorn)并且在某些 Python 版本中比_DEFAULT_CIPHERS更紧,但它既是内部的,也没有在任何地方使用 - 但已经至少从 3.4 开始维护。

所以选项 3 默认为 Python 的默认密码套件。

不这样做的唯一原因是,如果我们认为我们今天可以发布一个比旧 Python 版本更安全的列表,或者我们想要选择加入更严格的 OWASP 级别之一。 老实说,这是非常微不足道的。

所有3条评论

感谢您报告此问题。 我们非常清楚这一点。 Gunicorn 有一段时间没有对其 S​​SL 支持进行重大更改。 请参阅 #1933 以及该讨论中链接的问题。

同时,如果现在 Gunicorn 仅支持 Python 3.4+,如果有更明智的默认设置,请提交拉取请求,我很乐意合并它。 我们也在考虑将最低版本推高,因此如果有更高的最低 Python 版本可以启用更安全的默认值,请在此处发布该信息以帮助在下一个版本之前做出决定。

可用的密码(以及对SSLContext.set_ciphers()参数的解释)不受 Python 版本的影响,而是受 Python 构建所针对的 OpenSSL/LibreSSL 版本的影响。 在 Linux 上,这通常是发行版提供的版本。

如果您的问题是“我们能否设置一个始终适用于 Python 3.4+ 的更安全的默认值”,那么严格的答案是“否”,因为这取决于您编译 Python 的方式。 有可能针对缺乏强密码的非常旧的 OpenSSL 编译最近的 Python,因此在 gunicorn 中要求强密码可能意味着 SSL 根本不起作用。

不过,我认为我们很安全。 Python 3.4 于 2014 年发布,而添加了 TLSv1.2 的 OpenSSL 1.0.1a 于 2012 年 4 月发布。因此 Python 的发行版可能具有强密码。 另一件事是每个 Python 版本都需要一个特定的 OpenSSL 版本(例如,Python 3.7 需要 OpenSSL 1.0.2 我理解),但我不知道什么 Python 版本需要什么。

总的来说,我必须由 OWASP 指导。 他们说 C- 是“传统的,与真正的旧浏览器和遗留库的最广泛的兼容性”——还有一个额外的好处,那就是它们可以被引用为源代码。

此外,Python 有自己的默认密码列表:它永远不会回退到 OpenSSL 的默认值(显然是DEFAULT:!aNULL:!eNULL )。 它可以作为ssl._DEFAULT_CIPHERS访问,尽管这是内部/未记录的,因此访问默认值的方法是永远不要在 SSLContext 上调用 set_ciphers()。

对于 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'

在 Python 3.7 中它是

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

一条评论说“默认:OpenSSL 的默认密码列表。从 1.0.2 开始,列表的顺序是合理的。”

这些设置似乎非常紧凑,并且与 OWASP 具有相同的精神。

还有一个_RESTRICTED_SERVER_CIPHERS用于服务器(非常适合 gunicorn)并且在某些 Python 版本中比_DEFAULT_CIPHERS更紧,但它既是内部的,也没有在任何地方使用 - 但已经至少从 3.4 开始维护。

所以选项 3 默认为 Python 的默认密码套件。

不这样做的唯一原因是,如果我们认为我们今天可以发布一个比旧 Python 版本更安全的列表,或者我们想要选择加入更严格的 OWASP 级别之一。 老实说,这是非常微不足道的。

此页面是否有帮助?
0 / 5 - 0 等级