SSL错误是浏览器无法与网站建立可信加密连接时显示的信息。你得到的不是所请求的页面,而是一个警告界面,以及一个用小型大写字母显示的简短代码,类似NET::ERR_CERT_AUTHORITY_INVALID或SSL_ERROR_NO_CYPHER_OVERLAP这样的内容。
那个代码才是有用的部分,而大多数指南都跳过了它。”SSL错误”并不是一个技术术语,也没有任何标准对其进行定义。它是人们对一整类不同故障的通俗说法,这也是为什么诸如清除缓存之类的通用建议能修复其中一部分问题,而对其余部分则完全无效。
SSL错误究竟是什么
当你加载一个以https://开头的地址时,你的浏览器和服务器会在任何页面内容传输之前,先进行一次简短的协商,称为TLS握手。握手会商定协议版本和一组加密算法,服务器则用证书证明自己的身份。如果其中任何一个环节失败,浏览器就会拒绝继续,并向你显示错误信息而不是页面。
SSL和TLS在这里值得区分一下,因为这种命名确实会造成混淆。SSL是最初的协议,它的每个版本都已被弃用多年。你的浏览器实际使用的协议是TLS。”SSL”这个词依然保留在产品名称、配置指令和错误代码中,这也是为什么你到处都还能看到它。当某个页面或浏览器提到SSL时,它几乎总是指TLS。
这一点对故障排查很重要,因为关于SSL错误的通俗定义过于狭窄。你经常会读到,SSL错误意味着浏览器无法验证网站的证书。这对其中一类错误来说是对的,但对其余的则不对。一台服务器在HTTPS端口上以纯未加密文本回应,就会产生SSL错误,而且根本不会发送任何证书。两台无法就密码套件达成一致的机器,在证书被检查之前就已经产生了这种错误。当证书本来就不是问题所在时,却从证书入手排查,这正是人们把五分钟就能解决的问题拖成几个小时的最常见原因。
连接失败发生在哪个阶段
每一次HTTPS连接都会经过相同的一系列步骤,而SSL错误正是这个流程停止的那个点。判断出所处的阶段能立即缩小原因范围,因为每个阶段都有一套完全不同的解释。
- 连接从未成为TLS连接。你的浏览器打开了一个连接,但返回的内容不是TLS,或者对方在握手完成之前就关闭了连接。这里不涉及任何证书,也不需要更换证书。
- 握手在协商阶段失败。双方都使用TLS通信,但无法就协议版本、密码套件或请求的具体站点达成一致。握手在证书被验证之前就已停止,通常甚至在证书被发送之前就停止了。
- 证书已收到但被拒绝。这正是人们说”SSL错误”时通常所指的那一类。过期、主机名覆盖范围、信任链、吊销状态以及签名强度等问题都属于这一类。
- 握手成功,但之后的某个环节出了问题。加密连接已经正确建立,随后更上层的某个环节出现了故障。到这一步,证书已被确认无误,因此更换证书不会有任何改变。
你不需要去猜测自己处于哪个阶段。错误代码会告诉你答案,下一节将把每个代码对应到它所属的阶段。
找到你的错误
阅读警告信息下方打印出的代码。在Chrome和Edge中,它以小型大写字母显示在”您的连接不是私密连接”下方。在Firefox中,你可能需要打开警告页面上的高级详情。然后在下面查找它。
第一阶段:连接从未成为TLS连接
- SSL_ERROR_RX_RECORD_TOO_LONG在Firefox中意味着服务器对HTTPS请求的回应不是TLS,几乎总是在443端口上提供了普通HTTP服务。这是一个服务器配置问题。
- PR_END_OF_FILE_ERROR在Firefox中意味着对方在握手完成之前关闭了连接。原因通常出现在你和服务器之间的路径上,而不是在任何一端本身。
第二阶段:握手在协商阶段失败
- ERR_SSL_PROTOCOL_ERROR是Chrome针对无法准确识别原因的握手失败使用的通用代码。如果你遇到的正是这个代码,应从这里入手,因为首要任务是缩小范围。
- SSL_ERROR_NO_CYPHER_OVERLAP是Firefox的对应代码,同样含义宽泛:它会出现在服务器报告的任何致命握手失败中,无论服务器真正的原因是什么。
- ERR_SSL_VERSION_OR_CIPHER_MISMATCH是Chrome用于同一类失败的代码,针对一组简短而具体的协商条件而触发。
- ERR_SSL_UNRECOGNIZED_NAME_ALERT意味着服务器故意终止了握手,因为所请求的主机名在其配置中没有匹配的站点。此时不会发送任何证书,所以证书本身并没有问题。
- ERR_BAD_SSL_CLIENT_AUTH_CERT的方向与这里的其他所有错误相反:网站要求你的浏览器提供证书,却拒绝了它收到的证书,或者根本没有收到证书。这个问题确实需要在你自己的设备上修复。
- Cloudflare错误525是发生在整个连接路径中另一段的握手失败:发生在Cloudflare与其背后的源服务器之间,而不是在你的浏览器与Cloudflare之间。访问者对此无能为力。
第三阶段:证书已收到但被拒绝
您的连接不是私密连接是Chrome针对整个这一类错误显示的警告界面,而不是某种具体原因本身,所以如果你手头只有这个信息,先阅读它下方的代码。
信任链无法建立。浏览器无法将网站的证书追溯连接到其信任的根证书,通常是因为服务器只发送了自己的证书,而遗漏了它上层的中间证书。
- Chrome和Edge中的NET::ERR_CERT_AUTHORITY_INVALID。
- Firefox中的SEC_ERROR_UNKNOWN_ISSUER,是同一情况的不同名称。
- 过期的中间证书,信任链本身存在,但你上方的某一环已经过期。
- MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT,此时不存在信任链,因为该证书是自签名的。
日期或名称不匹配。证书本身是受信任的,但不适用于当前时刻或当前主机名。
- NET::ERR_CERT_DATE_INVALID,证书已过期或尚未生效。值得一提的是,你自己设备上的时钟设置错误同样会产生这个错误。
- NET::ERR_CERT_COMMON_NAME_INVALID,主机名未列在证书中。
- DLG_FLAGS_SEC_CERT_CN_INVALID,同样的主机名问题,由基于较旧Windows网络栈构建的软件报告,主要是Edge的Internet Explorer模式以及一些业务应用程序。
证书本身是受信任且有效的,但由于其他原因被拒绝。
- NET::ERR_CERT_REVOKED,证书颁发机构在其到期日之前已将其吊销。
- NET::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED,证书到达时没有携带足够的公开签发证明。
- NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM,信任链中的某个证书使用SHA-1签名。当前版本的Chrome可能会用不同的代码报告同一个证书问题,但情况和修复方法并没有改变。
- SEC_ERROR_REUSED_ISSUER_AND_SERIAL,这是Firefox自身证书存储中的冲突,而不是连接本身的故障。
- NET::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN,这适用于浏览器内置的极少数域名,普通网站不会产生这个错误。
证书文件本身有问题。以下这两种情况出现在服务器上而不是浏览器中,通常会导致网站完全无法提供HTTPS服务。
- ERR_SSL_SERVER_CERT_BAD_FORMAT,浏览器无法解码服务器发送的证书。
- 模数不匹配,安装的证书与安装的私钥不匹配。
第四阶段:握手成功,但之后出现了问题
这些错误因习惯而被归入SSL错误之列。在每一种情况下,加密连接已经正常工作,所以证书已经成功通过验证,重新签发证书并不会有帮助。
- ERR_SSL_BAD_RECORD_MAC_ALERT意味着服务器收到了它无法验证的加密数据,这发生在握手之后、会话密钥之下的层面。路径中的某个环节正在破坏或篡改流量。
- ERR_QUIC_PROTOCOL_ERROR是QUIC协议的失败,QUIC是HTTP/3底层所用的传输协议。这不是证书问题,常见原因是防火墙或VPN过滤了UDP流量。
- ERR_SPDY_PROTOCOL_ERROR是HTTP/2层面的失败,这一层位于已完成的TLS握手之上。
- 混合内容是个特例:页面已经通过HTTPS完全正常加载,随后又请求了一个通过普通HTTP传输的资源。它根本不会产生任何错误页面,只会出现一个降级的锁形图标,以及缺失的脚本或图片。
以设备而非阶段命名的错误
有两个平台各自产生了足够多独特的问题,值得单独说明,因为同样的底层情况在它们上面的表现方式不同。
- iPhone和iPad上的SSL错误,包括”发生SSL错误,无法与服务器建立安全连接”这条提示信息。首先要检查的是日期和时间设置。
- Android上的SSL连接错误,Chrome和其他应用程序在这里会查询不同的信任存储,缺失的中间证书在这里造成的麻烦比在桌面设备上更严重。
已不再出现的代码
有三个代码目前仍被广泛写入各种教程中,但已经从产生它们的浏览器中被移除,所以如果你在阅读关于其中任何一个的建议,先检查一下发布日期。其中两个代码背后的问题依然存在,只是以其他名称出现。
- NET::ERR_CERT_SYMANTEC_LEGACY已在2025年4月发布的Chrome 136版本中被删除。
- ERR_SSL_VERSION_INTERFERENCE在2019年的Chrome 76版本中被移除,尽管它所描述的干扰现象仍然存在,现在只是以不同的方式表现出来。
- ERR_SPDY_PROTOCOL_ERROR在2019年的Chrome 77版本中被重命名为ERR_HTTP2_PROTOCOL_ERROR。它所描述的故障目前依然存在,这也是为什么它被列在上文第四阶段中的原因。
如果你是网站访问者
大多数SSL错误需要由网站方来修复,无论你在自己的设备上做多少工作都无法改变这一点。这里确实存在少数真正的例外情况,在断定网站本身出了问题之前,值得先逐一排查一下。
- 检查你的时钟。证书验证会将证书的日期与你设备自身的时间进行比对。如果时钟偏差达数月甚至数年,就会让每个证书看起来都无效,这是访问者一端最常见的单一原因。
- 尝试换一个网络。从Wi-Fi切换到移动数据网络,或者反过来操作,几秒钟内就能告诉你网络中是否有东西在拦截流量。公共Wi-Fi和酒店Wi-Fi是常见的罪魁祸首。
- 暂时关闭HTTPS扫描。防病毒软件和企业代理会通过用它们自己的证书替换原有证书来检查加密流量。当它们处理不当时,你就会在其他地方运行正常的网站上遇到SSL错误。
- 尝试使用隐私窗口和另一个浏览器。如果错误只出现在一个浏览器中,而在另一个浏览器中没有,原因通常是本地的,出在某个扩展程序或存储的数据上。如果所有浏览器都出现同样的错误,那问题就出在网站上。
如果以上方法都没有帮助,那么问题就出在服务器上,老实说,你自己是无法修复的。这完全适用于Cloudflare错误525的情况,因为该故障发生在一个你的浏览器根本没有参与的连接上。
浏览器确实提供了绕过大多数证书警告继续访问的方式,但值得说清楚这样做的代价。继续访问意味着让浏览器接受一个它无法验证身份的连接,这也意味着你无法确定自己是在与你输入的那个网站通信,而不是与位于中间的某个东西通信。在你自己控制的测试服务器上,这是可以接受的取舍。但在任何你将要输入密码或支付信息的场合,这是不可接受的。有些错误根本不提供绕过的选项,这是有意为之,而不是故障。
如果你是网站运营者
在做任何改动之前先做诊断。重新安装一个从来就不是问题所在的证书,是让一小时变成一整个下午的常见方式。
从外部检查开始
用我们的SSL Checker检查该域名。它会报告服务器实际向外部世界发送的内容,这经常与配置文件中实际存在的内容不同。磁盘上看起来完整、但到达浏览器时却不完整的信任链,是最常见的发现,也是导致NET::ERR_CERT_AUTHORITY_INVALID和SEC_ERROR_UNKNOWN_ISSUER的原因所在。
你也可以从命令行看到同样的信息。以下命令会按照服务器提供的顺序,打印出它提供的每一个证书:
openssl s_client -connect example.com:443 -servername example.com -showcerts
阅读该输出中的证书列表,而不是底部的Verify return code那一行。那一行提供的信息远没有看起来那么充分:它只报告OpenSSL对信任链的判定结果,除非你明确要求进行主机名检查,否则它会忽略主机名,而且即使因为握手被中止而服务器根本没有发送证书,它也会打印出0 (ok)。如果输出显示no peer certificate available,而不是显示一行subject=,那说明什么都没有被验证,故障发生在更早的环节。
检查日期和主机名
这两项占据了证书被拒绝原因中的很大一部分。要查看服务器所提供证书的有效期范围:
openssl s_client -connect example.com:443 -servername example.com </dev/null | openssl x509 -noout -dates -subject
浏览器会将主机名与subjectAltName扩展进行匹配,而完全忽略Common Name字段,所以这才是检查本地证书文件时应该查看的字段:
openssl x509 -noout -text -in certificate.crt | grep -A1 "Subject Alternative Name"
要让OpenSSL执行浏览器所使用的那种主机名检查,应添加相应的标志,而不是假定一个干净的结果就已经涵盖了这项检查:
openssl s_client -connect example.com:443 -servername example.com -verify_hostname example.com
在macOS上,这些命令需要特别注意。macOS自带的openssl实际上是LibreSSL,它会直接拒绝-verify_hostname选项,而且在一些实际上存在缺陷的信任链上会报告健康的结果。请通过Homebrew安装OpenSSL,然后再次运行openssl version,确认你实际调用的是哪个二进制文件。如果它仍然报告是LibreSSL,说明你的PATH优先找到了系统自带的那个副本,此时应通过完整路径调用/opt/homebrew/bin/openssl。
然后进行修复和验证
应该改动什么,取决于所处的阶段,上文链接的各个具体指南中提供了针对各平台的具体步骤。以下三项修复涵盖了大多数情况:
- 提供完整的信任链。将你的证书与证书颁发机构提供的中间证书拼接到你服务器所指向的那个文件中。不要把私钥放进那个文件里。
- 在到期前续订,并将其自动化。证书的有效期正在不断缩短,因此任何手动续订的证书最终都会出现续订延迟的情况。ACME自动化能消除这个截止日期带来的压力。
- 覆盖你实际提供服务的每一个主机名。某个域名的证书并不会自动覆盖它的子域名,除非该证书是通配符证书或明确列出了这些子域名。
在重新加载服务之前,始终先测试配置,之后再从你自己网络之外重新运行检查工具。只在你一直用来测试的那个浏览器中确认修复效果并不算真正确认,因为该浏览器可能保留着一个缓存的结果。
如何预防SSL错误
一个正常运行的网站上出现的几乎每一个SSL错误,都来自以下三种情况之一:证书已过期、信任链从来就不完整,或者配置发生了偏移。这三种情况都是可以预防的。
- 自动化续订流程。证书的最长有效期在未来几年内将分阶段缩短,手动续订在这个期限结束之前很久就会变得不再现实。现在就把它自动化,而不是等到出问题才动手。
- 独立监控到期时间。日历提醒会在负责人离职时失效。而一个能提前数周向你发出警报的外部检查工具则不会。
- 每次改动后都重新检查。服务器迁移、CDN变更以及控制面板更新,都会悄无声息地重写证书配置。之后要从外部进行验证。
- 在手机上测试,而不仅仅是在桌面设备上。移动平台对不完整的信任链要求更严格,所以信任链的问题往往在手机上暴露出来,而桌面设备看起来却一切正常。
- 第一次就正确安装。我们的安装教程涵盖了各平台的信任链和绑定步骤,而大多数信任链错误都源于安装环节。
常见问题解答
这意味着你的浏览器无法建立一个同时能加密并可信任的连接,因此它拒绝加载页面,而不是在没有这些保证的情况下继续。这是一个大类,而不是单一的故障,涵盖四种不同的失败情况:连接从未承载TLS,双方无法就加密条款达成一致,证书被拒绝,或者加密连接工作正常但后续某一层出了问题。警告下方显示的代码会指明具体属于哪一种。
通常出在网站上。最快的测试大约只需一分钟:在另一台设备上、用另一个网络打开同一个地址,例如用移动数据打开手机上的浏览器。如果那里也失败,问题就出在服务器上,只有其运营方才能修复。如果那里能正常打开,原因就在本地,可能的原因包括你的时钟设置、正在检查HTTPS流量的防病毒软件、浏览器扩展程序,或者你所连接的网络。
有可能危险。继续访问意味着接受一个浏览器无法验证其身份的连接,这样你就失去了确认自己正在与真实网站通信、而不是与介于你和该网站之间的某个东西通信的保障。在你自己控制的开发服务器上,这是一个合理的取舍。但在任何你将要输入密码、银行卡号或个人信息的网站上,这就不合理了。有些错误故意不提供任何继续访问的方式,这是出于安全考虑的决定,而不是缺陷。
浏览器对证书的验证方式并不完全一致。它们内置的根证书列表不同,在吊销和证书透明度方面采用的策略也不同,而且对同一个底层情况会使用不同的名称,这也是为什么一个不完整的信任链在Chrome中显示为NET::ERR_CERT_AUTHORITY_INVALID,而在Firefox中显示为SEC_ERROR_UNKNOWN_ISSUER。同一台设备上不同浏览器之间出现差异,通常指向本地原因,例如某个扩展程序或存储的数据,因为一个真正出问题的服务器往往会在所有浏览器中都失败。
最常见的原因是证书信任链不完整。移动平台对服务器遗漏中间证书的情况更加不宽容,所以桌面浏览器能够容忍并恢复的同一种错误配置,在手机上却会导致失败。这种情况下确实是服务器端的真实问题,而不是手机的问题,用手机测试是发现这类问题的好方法。另一个常见原因是设备时钟,尤其是在一台长时间关机的手机上。
在日常使用中,这两个说法经常被互换使用,但了解它们之间的区别很有价值,因为这决定了你应该从哪里入手排查。SSL证书错误具体指上文所说的第三阶段,即证书已收到但因过期、主机名覆盖范围、信任问题、吊销状态或签名强度而被拒绝。SSL错误则是一个更广泛的类别,还包括从未涉及证书的失败情况,例如服务器在HTTPS端口上以纯文本方式回应,或者两台机器无法就密码套件达成一致。如果你在寻找解决方案,具体的错误代码会比这两个笼统的说法更快地帮你找到答案。
是的,而且这种情况很常见。第一阶段和第二阶段的错误发生在证书被验证之前,其中有几种情况根本没有发送任何证书。第四阶段的错误则发生在证书已经成功通过验证之后。在这两种情况下重新签发一个有效的证书都不会带来任何改变,这也是为什么在采取行动之前先确定所处的阶段能节省最多的时间。

