在非常旧的浏览器上连接 Discourse 时出现 SSL/TLS 错误

在使用默认的 Let’s Encrypt 支持设置我的 Discourse 实例后,我收到了一些用户的报告,称他们的浏览器无法与 Discourse 建立安全连接。其中一张用户提供的截图清楚地表明这是一个 SSL/TLS 错误。这是一个浏览器端的错误,用户甚至无法看到 Discourse 的任何内容。

根据上下文,这些用户似乎使用的是较旧的操作系统或浏览器。我最初怀疑问题是 TLS 1.2 支持,但我检查的一位用户正在 macOS(版本未知)上运行 Safari 10.1.2,而根据 Can I use... Support tables for HTML5, CSS3, etc 从第 7 版起就应该支持 TLS 1.2。

除了 TLS 1.2 之外,是否还有其他原因会导致浏览器/操作系统无法与使用 Let’s Encrypt 默认 TLS 支持的默认 Discourse 安装建立安全连接?我正在尝试确定应该向用户提出哪些问题,以找出他们的问题所在,并确定问题应在哪一端解决。

作为临时解决方案:据我所知,默认设置是将发往 http 的流量重定向到 https。是否可以先进行检查,例如“仅当浏览器支持 TLS 1.2

您可以使用 SSL 服务器测试 来测试您的网站。测试结果中包含一个名为“握手模拟”的部分,其中会显示哪些浏览器/操作系统组合可以正常工作,哪些无法工作。

在使用最新的 Docker 镜像时,我看到的 TLS 配置如下:

您可以将用户引导至 https://www.ssllabs.com/ssltest/viewMyClient.html,以获取有关其浏览器和操作系统版本以及支持的 TLS 版本的更多信息。

感谢您详细的回复!

我运行了 SSL 服务器测试,结果显示一切正常,未发现任何问题:

根据我的观察,结果与您在帖子中提到的完全一致。

唯一的失败项是旧版操作系统搭配 Safari 版本(Safari 8 和 9),以及旧版 Windows 系统搭配 IE 11。最后这一点让我有些担忧:Discourse 难道不应该支持 IE 11,并且默认支持 TLS 1.2 吗?

此外,该测试似乎未包含在仍受支持的最旧操作系统上运行 Safari 10 的测试,因此该组合也可能存在问题……

对于使用旧版 Windows 的用户,您可能需要启用 CBC 密码套件:

接下来,您应该引导这些用户访问

以获取有关其浏览器支持情况的信息。分享结果的最简便方式可能是让他们将结果打印为 PDF 文件并发送给您。

谢谢,我收到了用户的回复。他们正在使用一款非常老旧的 iPod Touch:

您浏览器的 SSL/TLS 能力
用户代理: Mozilla/5.0 (iPod; CPU iPhone OS 6_1_6 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B500 Safari/8536.25

协议支持

您的用户代理具有良好的协议支持。

您的用户代理支持 TLS 1.2,这是目前推荐的协议版本。

因此,虽然它很老旧(我也清楚它远未达到 Discourse 最低支持的操作系统和浏览器要求),但我还是希望至少能让他们连接到网站,看看他们的浏览器在现代 HTML 和 JavaScript 方面的表现如何。

以下是详细的 TLS 支持报告:

协议特性

协议

TLS 1.3 否
TLS 1.2 是
TLS 1.1 是
TLS 1.0 是
SSL 3 是
SSL 2 否

密码套件(按偏好顺序)

TLS_EMPTY_RENEGOTIATION_INFO_SCSV ( 0xff ) -
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 ( 0xc024 ) 256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 ( 0xc023 ) 128
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA ( 0xc00a ) 256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA ( 0xc009 ) 128
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA ( 0xc007 ) 不安全 128
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA ( 0xc008 ) 112
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 ( 0xc028 ) 256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 ( 0xc027 ) 128
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA ( 0xc014 ) 256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA ( 0xc013 ) 128
TLS_ECDHE_RSA_WITH_RC4_128_SHA ( 0xc011 ) 不安全 128
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA ( 0xc012 ) 112
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 ( 0xc026 ) 256
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 ( 0xc025 ) 128
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 ( 0xc02a ) 256
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 ( 0xc029 ) 128
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA ( 0xc004 ) 128
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA ( 0xc005 ) 256
TLS_ECDH_ECDSA_WITH_RC4_128_SHA ( 0xc002 ) 不安全 128
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA ( 0xc003 ) 112
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA ( 0xc00e ) 128
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA ( 0xc00f ) 256
TLS_ECDH_RSA_WITH_RC4_128_SHA ( 0xc00c ) 不安全 128
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA ( 0xc00d ) 112
TLS_RSA_WITH_AES_256_CBC_SHA256 ( 0x3d ) 256
TLS_RSA_WITH_AES_128_CBC_SHA256 ( 0x3c ) 128
TLS_RSA_WITH_AES_128_CBC_SHA ( 0x2f ) 128
TLS_RSA_WITH_RC4_128_SHA ( 0x5 ) 不安全 128
TLS_RSA_WITH_RC4_128_MD5 ( 0x4 ) 不安全 128
TLS_RSA_WITH_AES_256_CBC_SHA ( 0x35 ) 256
TLS_RSA_WITH_3DES_EDE_CBC_SHA ( 0xa ) 112
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 ( 0x67 ) 128
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 ( 0x6b ) 256
TLS_DHE_RSA_WITH_AES_128_CBC_SHA ( 0x33 ) 128
TLS_DHE_RSA_WITH_AES_256_CBC_SHA ( 0x39 ) 256
TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA ( 0x16 ) 112
TLS_ECDHE_ECDSA_WITH_NULL_SHA ( 0xc006 ) 不安全 0
TLS_ECDHE_RSA_WITH_NULL_SHA ( 0xc010 ) 不安全 0
TLS_ECDH_ECDSA_WITH_NULL_SHA ( 0xc001 ) 不安全 0
TLS_ECDH_RSA_WITH_NULL_SHA ( 0xc00b ) 不安全 0
TLS_RSA_WITH_NULL_SHA256 ( 0x3b ) 不安全 0
TLS_RSA_WITH_NULL_SHA ( 0x2 ) 不安全 0
TLS_RSA_WITH_NULL_MD5 ( 0x1 ) 不安全 0
(1) 当浏览器支持 SSL 2 时,其仅支持 SSL 2 的套件仅在首次访问此站点时显示。要查看这些套件,请关闭所有浏览器窗口,然后直接打开此页面。请勿刷新。

协议详情

服务器名称指示 (SNI) 是
安全重协商 是
TLS 压缩 否
会话票据 否
OCSP 装订 否
签名算法 SHA384/RSA, SHA256/RSA, SHA1/RSA, SHA256/ECDSA, SHA1/ECDSA
命名曲线 secp256r1, secp384r1, secp521r1
下一协议协商 否
应用层协议协商 否
SSL 2 握手兼容性 否

混合内容处理

混合内容测试
图片(被动)是
CSS(主动)是
脚本(主动)是
XMLHttpRequest(主动)是
WebSockets(主动)是
框架(主动)是
(1) 这些测试可能会在您的浏览器中引发混合内容警告。这是正常的。
(2) 如果您看到测试失败,请尝试重新加载页面。如果错误仍然存在,请联系我们。

抱歉格式有些混乱,用户将富文本 HTML 复制粘贴给了我,其中部分内容在粘贴到 Discourse 时丢失了。我稍后会尝试找出如何修复格式问题。

正如我所说,我希望至少能让他们建立安全连接,这样他们就能看到一些内容。鉴于他们的浏览器支持 TLS 1.2,这应该是可行的。但我猜我必须为 TLS 1.2 启用一些安全性较低的配置,才能支持他们的浏览器。我对 TLS 配置还不够了解,无法将这份报告的输出与服务器支持的内容以及我需要更改的内容对应起来。您能告诉我缺少了什么,以及我需要更改哪些内容吗?

我大概明白你的意思,但完全不知道具体该怎么做。能否指点我查阅一些文档,说明如何修改 Discourse Docker 容器的 TLS 配置以启用这些密码套件?

即使通过添加额外的密码套件解决了 TLS 问题,我认为 Safari 6 仍然无法正常工作。

你可以通过覆盖 nginx 配置文件来添加缺失的密码套件。将以下代码片段(未经测试,但应该可行)添加到 app.ymlhooks 部分,并根据需要修改 ssl_ciphers 的值。

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

顺便一提:我正在尝试为 Discourse 添加对椭圆曲线证书的支持,这将使其能够直接支持 IE11。

iOS 6?!该版本的最后一个版本发布于 2014 年初!那已经是 5 年多以前的事了!

我知道,我和你一样感到惊讶。我不指望你支持它,但我希望用户至少能获取一些 HTML 代码,看看哪些能用,哪些不能用。

感谢 @gerhard,我已按照您的描述对 /var/discourse/containers/app.yml 进行了修改(希望这是正确的 app.yml 文件),然后按照 app.yml 注释中的说明运行了 /var/discourse/launcher rebuild app

随后我重新在 ssllabs.com 上运行了测试,但结果似乎没有变化:https://www.ssllabs.com/ssltest/analyze.html?d=forum.stadtteilgenossenschaft-wik.de&s=68.183.214.228&hideResults=on

我不确定如何验证配置更改是否真正生效(但它并未影响测试结果),或者配置更改是否根本没有起作用。

哦,@gerhard,我没有正确理解你的帖子。如果我没理解错的话,你提供的配置确实会明确指定使用的加密套件,但你用的值基本上和默认值一样,对吧?所以我仍然需要扩展它,添加其他可能支持旧版浏览器的加密套件。

是的,没错。我不想直接发布在配置中添加弱密码的解决方案,这个问题需要你自己解决。:wink:

不过,如果你要进行这些修改,建议留意我之前提到的那个拉取请求。一旦它被合并,IE11 就能直接正常工作。

我明白了,你不想让设置变得太容易导致不安全。我尊重这一点,也不会发布完整的代码。

以下是我目前的进展:我通过查看例如 https://www.ssllabs.com/ssltest/viewClient.html?name=Safari&version=6&platform=iOS%20%206.0.1&key=33(以及其他浏览器/操作系统)来识别缺少哪些密码套件以支持旧版浏览器和操作系统。由于客户端密码套件是按优先级列出的,我只需选择列表中最靠前的一个,并确保服务器支持它,假设只要服务器支持列表中的某个套件就足够了。我识别出的密码套件如下:

  • ECDHE-ECDSA-AES256-CBC-SHA384 用于 Safari 6-8
  • ECDHE-RSA-AES256-CBC-SHA384 用于 Win 7/8.1/Phone 8.1 Update 上的 IE 11(根据 @supermathie 的说法)
  • ECDHE-RSA-AES128-CBC-SHA256 用于 Win Phone 8.1 上的 IE 11

我将这些值添加到 ssl_ciphers 列表的末尾,用冒号分隔,假设“列表末尾”意味着“优先级最低,仅在客户端不支持其他套件时使用”。然后我运行了 /var/discourse/launcher rebuild app 以应用新配置,并在清除缓存后重新运行了 SSL Server Test (Powered by Qualys SSL Labs) 上的测试。但结果没有变化。

我原本期望现在 IE 11 和 Safari 6-8 的测试都能成功,但握手仍然失败。所以我一定漏掉了什么。

另外,我的一个用户使用 iPhone 运行 iOS 9/Safari 9,他们的连接也失败了。但根据 SSL Labs 的测试结果,该连接本应开箱即用(正如 @gerhard 上方的结果 中所示)。

所以我一定漏掉了两件事:

  1. 为什么在添加了对这些密码套件的支持后,连接仍然无法工作?
  2. 为什么 SSL Labs 显示 iOS 9 + Safari 9 可以工作,但实际上我的用户却无法连接?

关于第 1 点:我仍然不确定是否正确应用了配置。除了 SSL Labs 测试外,还有其他方法可以检查服务器支持哪些密码套件,以确认我的配置更改是否真正生效吗?

仔细查看 SSLLab 的结果后,我认为这不起作用。

应用配置并重新构建后,我在 SSLLabs 上看到的服务器结果如下:

据我理解,它应该列出更多内容,因为配置中包含更多选项。这是否意味着此配置更改未生效?

我认为您选择的密码套件名称有误。Mapping OpenSSL cipher suite names to IANA names 是一个很好的资源,可用于映射 SSL 服务器测试中列出的密码套件与 OpenSSL(nginx)使用的名称。

在我的测试中,我追加了 :ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA,重新构建后测试结果如下:

也许是测试本身存在 bug?:man_shrugging: 我没有那么旧版本的 Safari 进行测试。我们仅支持 Safari 10 及以上版本。您确定问题仍然是由 TLS 错误引起的吗?

谢谢,我会试试!

我进一步查看了 Discourse 的配置文件,发现了 templates/web.ssl.template.yml。通过 app.yml 文件修改密码套件,与直接在 templates/web.ssl.template.yml 中修改 ssl_ciphers 列表,这两者有什么区别?

模板是受版本控制的,而 app.yml 不是。如果你直接编辑模板,在更新仓库时会遇到问题。

谢谢,这正是问题所在。修正名称后,所有在 SSLLabs 列表中测试过的浏览器都能成功完成握手。非常感谢你的耐心!

现在,我很好奇用户在使用旧浏览器绕过 HTTPS 错误后,会看到什么内容。:smiley: