1. SSL/TLS警告协议概述
- 警告协议(Alert Protocol)是SSL/TLS协议栈的一部分,它用于在两个通信对等实体之间传输关于连接状态、错误或其他重要条件的通知。当加密会话中发生异常或错误时,一方可以通过发送一个警告消息来通知另一方。
2. 警告协议组成
- 警告协议中的消息格式由两个基本组成部分:警告错误级别和警告协议的详细描述信息
- 警告协议结构
-
struct{ AlertLevel level; //警告错误级别 AlertDescription description; //警告协议的详细描述信息 } Alert;
2.1 警告错误级别
- 警告错误级别主要有以下两种
- warning : 表示非致命性问题,不影响当前会话的继续,但可能表明存在潜在的安全风险或配置问题
- fatal : 最严重的级别,指示出会话必须立即终止的情况
- 警告错误级别结构
-
enum{ warning(1), fatal(2), (255) } AlertLevel;
2.2 警告协议的详细描述信息
-
警告协议的详细描述信息大概有以下25种
-
警告协议的详细描述信息结构
-
enum { close_notify(0), //正常关闭通知,表示会话正常结束。 unexpected_message(10) , //表示收到了不适当或未预期的消息类型 bad_record_mac(20), // 记录层的消息认证码(MAC)验证失败 decryption_failed_RESERVED(21), //解密接收到的数据时出现了问题 record_overflow(22), //接收到的数据记录长度超过了协议所规定的最大长度,违反了协议的格式要求 decompression_failure(30), //解压缩操作失败 handshake_failure(40), // 握手过程中发生错误,无法完成握手 no_certificate_RESERVED(41), //未接收到有效证书 bad_certificate(42), //证书无效或格式错误 unsupported_certificate(43), //对端提供的证书不受本地信任存储支持 certificate_revoked(44), //证书已被吊销 certificate_expired(45), //证书已过期 certificate_unknown(46), //无法验证对端提供的证书的有效性 illegal_parameter(47), //在握手消息中遇到了非法或不支持的参数 unknown_ca(48), //验证过程中使用的证书颁发机构未知 access_denied(49) , //访问被拒绝 decode_error(50), //解码消息时出错 decrypt_error(51) , //解密消息时出错 export_restriction_RESERVED(60), protocol_version(70), //不支持的协议版本 insufficient_security(71), //安全度低于最低要求 internal_error(80), //发生了内部错误 user_canceled(90) , // 用户主动取消了相关操作 no_renegotiation(100) , //客户端或服务器拒绝重新协商请求时产生 unsupported_extension(110) , //一方接收到的SSL/TLS扩展不被另一方支持或理解 (255) } AlertDescription;
3. 警告信息含义及解决方案
- 下面给出一些常见握手警告消息的含义和理论上的解决方案。
3.1 close_notify
-
含义
- 该消息是SSL/TLS协议中的一个正常消息,它用于通知对方即将关闭连接。当正确关闭一个SSL/TLS连接时,通信双方会通过发送并接收close_notify消息来确保安全地结束会话。然而,如果在握手阶段就收到close_notify,或者在非正常情况下收到了close_notify,那么可能的原因包括
- 服务器端主动关闭了连接:这可能是由于服务器配置问题、服务器负载过高、服务重启、超时设置不合理等原因导致的。
- 客户端(如浏览器)在握手过程中发现了一些不可接受的安全问题,比如证书验证失败、加密套件不匹配等,从而提前终止了连接。
- 网络中断或数据包丢失,导致close_notify消息没有被正确处理。
-
解决方案
- 检查并确认服务器的SSL/TLS证书是否有效、是否由受信任的CA签发,并且与服务器主机名匹配。
- 查看服务器的SSL/TLS配置,确保使用的加密套件和协议版本是客户端支持的。
- 检查网络状况,排除网络层面的问题。
- 查看服务器日志以获取更详细的错误信息,进一步定位问题所在。
3.2 unexpected_message
- 含义
- 通常意味着客户端或服务器接收到的消息不符合预期的握手协议流程。这可能由以下原因导致
- 消息格式不正确
- 发送的数据包内容或者结构不符合SSL/TLS协议的规定,比如包含了不匹配的加密套件、证书或者其他非标准信息。
- 版本协商失败
- 客户端和服务器之间对于要使用的SSL/TLS版本无法达成一致,发送了对方无法理解的消息格式。
- 密钥交换问题
- 在密钥交换过程中出现了错误,例如客户端或服务器没有按照约定的方式生成或使用会话密钥
- 中间件干扰
- 代理服务器或其他网络设备对SSL/TLS流量进行了错误的操作,导致原始数据被破坏或改变
- 软件或库兼容性问题
- 使用的SSL/TLS实现存在bug,或者不同版本间的兼容性问题,导致一方发出的消息另一方无法解析
- 解决方案
- 检查客户端与服务器之间的SSL/TLS版本是否匹配
- 确保使用的加密套件是双方都支持的。
- 查看服务器和客户端的日志文件,获取详细的错误信息,以便定位具体的问题点。
- 如果有网络中间件(如负载均衡器、防火墙等),检查其配置以确保它们不会影响SSL/TLS握手过程。
- 更新客户端或服务器的软件版本,包括但不限于浏览器、Web服务器、应用服务器以及相关的安全组件,以确保使用的是无已知漏洞的最新版本。
3.3 bad_record_mac
- 含义
- 在传输层安全协议的数据解密阶段发生了错误。MAC(Message Authentication Code)是用于确保数据完整性和防篡改的机制,它通常与加密算法一起使用,以验证收到的消息是否在传输过程中被修改。这可能由以下原因导致
- 数据完整性问题
- 数据在传输过程中可能由于网络问题或恶意攻击而受损,导致MAC校验失败。
- 密钥不匹配
- 客户端和服务器使用的会话密钥或记录密钥不一致,因此无法正确计算或验证MAC值。
- 软件或硬件故障
- 服务端或客户端软件存在bug,或者硬件设备(如加密卡)在处理MAC时出现问题。
- 协议实现兼容性问题
- SSL/TLS的不同版本或者不同实现之间的兼容性问题可能会导致MAC计算或验证失败。
- 中间件干扰
- 网络中的代理、负载均衡器或其他设备可能错误地处理了SSL流量,影响了MAC的有效性。
- 解决方案
- 检查并确认客户端和服务端都支持相同的SSL/TLS版本,并且配置了正确的加密套件。
- 检查网络连接是否有潜在的数据包丢失或损坏的情况,如有必要,调整网络设置或排查网络设备问题。
- 更新客户端和服务器上的SSL/TLS库或组件到最新版本,确保它们修复了已知的问题。
- 在服务器端检查SSL证书及其私钥配置是否正确无误。
- 如果有网络中间件参与通信,检查其配置并确保对SSL流量的处理方式正确。
- 对于ILO (Integrated Lights-Out) 或其他远程管理接口等特定场景,有时需要调整浏览器的安全设置或更新固件版本来解决此类SSL/TLS握手问题。
3.4 record_overflow
- 含义
- 表示接收到的数据包中的记录长度超过了协议允许的最大值。根据SSL/TLS协议规范,数据报文被分割成多个记录进行传输,每个记录都有其最大尺寸限制。当服务器或客户端接收到一个超出该限制的记录时,就会抛出“record_overflow”错误。这种情况可能由以下原因引起
- 攻击行为
- 这可能是由于恶意攻击者试图通过发送超大尺寸的记录来干扰或破坏通信,这种行为可能属于拒绝服务攻击(DoS)的一种形式。
- 软件实现问题
- SSL/TLS库或者应用程序可能存在编程错误,导致在构建或处理数据记录时未能正确遵守协议规定,从而生成了过大的记录。
- 网络层问题
- 在数据传输过程中,网络设备或中间件可能出现异常,导致数据包的重组或分片不正确,使得接收端收到的单个SSL/TLS记录看上去超出了协议规定的大小限制。
- 解决方案
- 检查和更新客户端及服务器上使用的SSL/TLS库版本,确保它们没有已知的溢出错误。
- 分析网络流量以确定是否存在异常的大尺寸数据包,并排查网络设备、防火墙、负载均衡器等是否对SSL/TLS流量进行了不当处理。
- 如果怀疑遭受攻击,应加强网络安全措施,例如部署深度包检测(DPI)系统以过滤恶意流量,并采取其他安全策略来抵御潜在的攻击。
3.5 handshake_failure
- 含义
- 该警告是一个常见的SSL/TLS连接错误,它发生在客户端和服务器尝试建立安全连接时未能就一组共同接受的安全参数达成一致。这个错误可能由以下几种原因导致
- 证书问题
- 服务器的SSL/TLS证书已过期或未在有效期内。
- 客户端不信任证书颁发机构(CA),或者证书链不完整。
- 服务器证书的域名与客户端尝试访问的域名不匹配。
- 加密套件协商失败
- 客户端和服务器支持的加密算法列表不重叠,双方无法找到一种共享的、可以用于握手过程的加密套件。
- 协议版本不兼容
- 客户端或服务器仅支持某些特定的SSL/TLS协议版本,而对方不支持这些版本。
- SNI(Server Name Indication)问题
- 如果服务器托管了多个SSL证书,并依赖SNI来确定使用哪个证书,但客户端不支持SNI,或发送的主机名不正确,可能会导致握手失败。
- 安全策略设置
- 客户端或服务器的安全策略可能过于严格,例如禁止了弱密码套件或特定协议版本。
- 中间件配置不当
- 反向代理、负载均衡器或其他网络设备可能对SSL握手过程进行了错误的配置。
- 解决方案
- 更新系统时间和日期确保准确无误。
- 确保服务器上的SSL/TLS证书是有效的且受信任的。
- 检查并调整服务器的SSL配置以支持多种加密套件和TLS协议版本。
- 确保SNI配置正确,特别是在多域名或多证书环境中。
- 对于客户端应用程序,检查其SSL/TLS设置是否可以接受服务器提供的证书和协议版本。
- 查阅服务器日志获取更详细的错误信息,以便进一步诊断。
3.6 no_certificate_RESERVED
-
含义
- 味着在要求客户端或服务器提供证书的场景下,没有接收到预期的证书。"RESERVED"在这里可能表示这是一个保留的错误代码,具体含义根据不同的SSL/TLS实现可能会有所差异。这个错误一般发生在以下情况
- 客户端认证:
- 当服务器配置为需要客户端证书时(例如双向认证),但客户端未能发送有效的客户端证书,就会导致此错误。
- 服务器证书缺失:
- 如果服务器端没有正确配置SSL证书或者证书路径不正确,当客户端尝试连接并验证服务器身份时,也会遇到类似问题。
- 协议处理异常:
- 在某些特定情况下,可能是由于SSL/TLS库内部处理机制的问题,比如对某个未定义或保留状态的误判。
-
解决方案
- 对于服务器端:
- 确保已安装正确的SSL/TLS证书,并且在服务器配置中指定了准确的证书文件路径和密钥文件路径。
- 检查服务器配置是否正确启用并请求了客户端证书(如适用)。
- 对于客户端:
- 如果是客户端连接到需要其提供证书的服务器,则确保客户端具有一个受服务器信任的有效证书,并将其正确配置到客户端软件中。
- 检查客户端的信任存储区,确认其中包含了可以验证服务器证书链所需的所有根CA和中间CA证书。
- 对于服务器端:
3.7 bad_certificate
- 含义
- 客户端或服务器在验证对方提供的证书时遇到了问题。这个错误具体指向以下几种可能情况
- 证书无效
- 证书可能已过期,即当前日期超出了证书的有效期范围。
- 证书的签名算法不被客户端信任或者已被淘汰不再支持。
- 证书没有正确地链到一个受信的根证书颁发机构(CA)。
- 证书撤销
- 如果证书已经被其签发者列入了撤销列表(CRL)或者在线证书状态协议(OCSP)响应表明该证书已被撤销,则会被认为是不可用的。
- 证书格式错误
- 证书文件可能损坏、不完整或者格式不符合规范。
- 域名/主机名不匹配:
- 客户端进行服务器身份验证时,会检查服务器证书中的Common Name (CN) 或 Subject Alternative Names (SANs) 是否与正在连接的服务器主机名相匹配,如果不匹配也会导致此错误。
- 双向认证问题
- 在需要客户端证书的场景下,如果客户端提供的证书不能被服务器接受或验证通过,也可能抛出“bad_certificate”错误。
- 中间证书缺失:
- 如果服务器证书链中缺少必要的中间证书,客户端无法建立完整的信任链,从而拒绝证书
- 解决方案
- 确保服务器上的SSL/TLS证书有效且未过期。
- 检查并更新服务器配置以包含所有必要的中间证书和根证书。
- 配置正确的主机名绑定,确保服务器证书的主体信息与客户端试图连接的主机名一致。
- 对于需要客户端证书的场景,确保客户端拥有有效的、受服务器信任的证书,并正确提供给服务器。
- 更新系统或应用程序的信任存储库,确保包含了服务器证书所需的所有受信任的CA证书。
- 检查并更新客户端和服务器上的SSL/TLS版本以及加密套件设置,确保它们都支持并且兼容。
3.8 unsupported_certificate
- 含义
- 意味着客户端(通常是浏览器或其他安全连接的发起方)无法支持或不信任服务器提供的证书。这个错误可能的原因包括
- 证书类型不受支持
- 证书可能是使用了特殊的、非标准格式或者不是X.509格式的证书,而客户端不支持这种类型的证书。
- 签名算法不被接受
- 证书使用的签名算法可能已过时或者不再受客户端支持,例如SHA-1等旧版签名算法已经被许多现代浏览器淘汰。
- 加密套件不匹配
- 服务器证书中包含的公钥对应的加密算法可能不在客户端支持的加密套件列表中。
- CA证书缺失或不受信任
- 如果服务器证书是由一个不受客户端信任的证书颁发机构(CA)签发,或者中间证书没有正确地提供给客户端,导致客户端无法验证证书链的有效性。
- 扩展属性问题
- 证书中的某些扩展属性可能不符合客户端的安全策略,例如一些特定的增强型密钥用法(Extended Key Usage, EKU)要求。
- 解决方案
- 确保服务器证书是标准的X.509证书,并且由一个普遍认可的、被客户端信任的CA签发。
- 更新服务器证书以使用更现代和广泛支持的签名算法。
- 检查并更新服务器配置,确保它发送的是客户端可以理解和支持的加密套件。
- 在需要的情况下,在服务器上正确配置完整的证书链,包括所有必要的中间证书。
- 对于自签名证书或内部CA签发的证书,将其根证书添加到客户端的信任存储区。
3.9 certificate_revoked
-
含义
- 意味着客户端在验证服务器提供的证书时发现该证书已经被撤销。这意味着
- 证书颁发机构(CA) 已经将此证书标记为不可用或无效,可能是由于私钥泄露、证书信息错误或其他安全原因。
- 证书撤销列表 (CRL):当客户端通过检查由证书颁发者发布的CRL时,如果发现当前的服务器证书在此列表中,那么就会报告证书已被撤销。
- 在线证书状态协议 (OCSP):另一种机制是OCSP,客户端可以通过实时查询OCSP响应服务器来确认证书是否有效。如果OCSP响应表明证书已被撤销,也会抛出这个错误。
-
解决方案
- 作为服务器管理员:
- 确认您的证书是否确实已被撤销,如果是,请联系证书颁发机构获取新的证书。
- 如果撤销是误报或者临时性问题,请与CA沟通,并确保您的服务器配置正确指向了最新的CRL分发点或OCSP响应器地址。
- 作为客户端应用开发者或用户:
- 更新系统或应用的信任存储库,确保包含了最新的证书撤销列表。
- 检查网络设置以确保客户端可以成功访问到CRL或OCSP响应服务器
- 作为服务器管理员:
3.10 certificate_unknown
- 含义
- 这通常表示客户端无法验证服务器提供的证书的有效性。这个错误可能源于以下几个原因:
- 证书未被信任 : 服务器证书没有被客户端的信任存储(或信任锚点)所包含。这意味着客户端无法找到一个可信任的路径来验证服务器证书是由一个受信任的证书颁发机构(CA)签发的。
- 证书过期:如果服务器证书已经过期,客户端会拒绝该证书,并可能导致“certificate_unknown”错误。
- 证书撤销:如果服务器证书已被发行者撤销但客户端尚未获取最新的吊销列表(CRL)或在线证书状态协议(OCSP)响应,则证书可能会被视为未知或无效。
- 证书域名不匹配:服务器证书上的Common Name (CN) 或Subject Alternative Names (SANs) 不包含或不匹配客户端正在连接的主机名。
- 中间证书缺失:如果服务器证书链中的中间证书未正确提供给客户端,客户端可能无法完成证书链验证,从而导致“unknown”错误。
- 证书损坏或格式错误:证书文件本身存在问题,如数据损坏、编码错误等,使得客户端无法正确解析和验证证书内容。
- 解决方案
- 确保服务器使用的是由受信任的证书颁发机构签发的有效证书。
- 检查并更新客户端的信任存储以确保其包含所有必要的根证书和中间证书。
- 验证服务器配置中是否正确地提供了完整的证书链。
- 核实服务器证书的域名与客户端试图访问的域名一致。
- 确保服务器时间设置正确,因为过时或未来的时间可能影响证书有效性检查。
- 对于开发或测试环境,如果有必要可以临时禁用SSL验证(仅限非生产场景),但这不是一个安全的做法,应在正式环境中严格遵循证书验证规则。
3.11 illegal_parameter
- 含义
- 意味着在SSL握手过程中客户端或服务器发送了一个参数,对方无法正确解析或接受。非法参数(illegal_parameter)的报错可能由以下原因引起
- 加密套件不匹配:客户端和服务器支持的加密套件列表可能不一致,导致协商过程中选择了不被双方都认可的参数。
- 协议版本问题:如果客户端和服务器之间对SSL/TLS协议版本的理解不同,可能会导致握手中的参数不符合预期。
- 证书问题:虽然不是直接关于证书本身的有效性,但与证书相关的参数(如公钥长度、签名算法等)若设置不当也可能引发此错误。
- 随机数无效:在SSL握手过程中,双方会交换随机数用于生成会话密钥,如果随机数不符合要求或者格式不正确,则会出现该错误。
- 密码参数错误:例如,在某些情况下,密钥交换过程中使用的DH(Diffie-Hellman)参数可能不合法。
-扩展参数配置错误:现代SSL/TLS协议允许各种扩展参数以增强安全性,如果这些参数设置不合理或不可识别,也会导致握手失败。
- 解决方案
- 确保客户端(通常是浏览器)和服务器都支持并配置了正确的SSL/TLS协议版本。
- 检查服务器端的SSL配置文件,确保所有加密套件和相关参数设置都是有效的,并且是客户端所支持的。
- 更新服务器上的SSL/TLS证书及其相关配置,尤其是与加密强度相关的设置。
- 确认防火墙、负载均衡器或其他网络设备没有干扰SSL握手过程,它们可能需要更新以支持特定的加密套件或协议版本。
- 对于自定义实现的SSL/TLS功能,检查代码以确保所有协议规定的参数都按规范设置。
3.12 unknown_ca
- 含义
- 该警告通常意味着客户端在验证服务器提供的SSL证书时,无法找到或识别颁发该证书的证书颁发机构(CA)。这个错误表示客户端的信任存储中没有包含用于验证服务器证书链完整性的中间证书或者根证书。
- 解决方案
- 检查服务器证书:确保服务器上的SSL证书是由一个受信任的CA签发的,并且证书链完整。如果使用的是自签名证书或者内部CA签发的证书,需要将相应的根证书或中间证书安装到客户端的信任存储中。
- 添加中间证书:如果证书是通过第三方CA签发并且包含中间证书,则需要确保这些中间证书也已经正确地配置在服务器上,以便客户端能够构建完整的证书信任链。
- 更新客户端的信任库:对于浏览器,请确保浏览器的信任存储是最新的,并包含了大多数主流CA的证书。如果服务器证书由非常见CA签发,可能需要手动下载并安装相关中间证书或根证书。
- 服务器配置:在服务器端,确认SSL配置是否正确指定了所有必要的证书文件,包括主证书和任何必需的中间证书。
- 时间同步:检查客户端设备的时间和日期设置,不准确的时间可能导致证书验证失败。
- 禁用严格SSL验证:在某些开发或调试场景下,可以暂时禁用严格的SSL验证,但这不是一个安全的做法,不应在生产环境中采用。
- 通过执行上述步骤,应该能解决大部分由于未知CA导致的SSL握手失败问题。不过,在生产环境中,始终建议遵循最佳实践,确保所有证书都来自可信源(证书从可信CA机构申请或购买),并且正确配置和分发给客户端。
3.13 protocol_version
- 含义
- 客户端和服务器之间无法就使用的SSL/TLS协议版本达成一致。这意味着客户端提出的SSL/TLS版本要么服务器不支持,要么服务器认为版本太旧而存在安全风险。
- 例如,当客户端尝试使用较旧的SSL 3.0版本进行连接,而服务器只支持TLS 1.2及以上版本时,服务器可能会向客户端发送一个包含"protocol_version"警告的握手失败消息。反之亦然,如果服务器希望使用较新版本的TLS,而客户端不支持,也会导致此警告。
- 解决方案
- 这种情况下,通常需要调整客户端或服务器的配置,使其能够支持共同的SSL/TLS协议版本,以保证安全、顺利地建立加密连接。
4. 实例演示
- 上面介绍的都是一些理论错误和解决方案,接下来实际复现下常见的握手警告。我这里使用的OpenSSL开源库来复现问题。
4.1 协议版本不匹配
- 即客户端使用的协议版本与服务端不匹配。
- 这里我指定客户端的协议版本为 TLS1.2,服务端的协议版本为TLS1.1。
- 访问服务后,服务端会有以下报错 140429813547520:error:1408F10B:SSL routines:ssl3_get_record:wrong version number:ssl/record/ssl3_record.c:299
- 抓包看下协议警告信息
- 可以看到警告信息为 protocol_version。
4.2 加密套件不支持
- 加密套件不支持,即服务端指定的加密套件客户端不支持。
- 我复现以下这个错误,在服务端指定了一个客户端不支持的加密套件。
- 服务端会有以下报错 140546601886208:error:1417A0C1:SSL routines:tls_post_process_client_hello:no shared cipher:ssl/statem/statem_srvr.c:2285
- 抓个包看下,是哪个警告消息。
- 可以看到警告消息是 handshake_failure 。
4.3 服务端校验客户端证书失败
- 双向认证的时候,服务端需要校验客户端证书。如果提交的客户端证书有问题,就会校验失败。
- 这里我们访问服务时随便提交一个证书,服务端就会有以下报错 139996670071296:error:1417C086:SSL routines:tls_process_client_certificate:certificate verify failed:ssl/statem/statem_srvr.c:3713
- 抓包看下警告消息为 certificate_unknown
4.4 客户端校验服务端证书失败
- 双向认证时,客户端也需要校验服务端证书,如果客户端的根证书有问题或者服务端提交的证书有问题,也会校验失败。
- 这里我们随便提交一个服务端证书,服务端就会报错 140249692172800:error:14094418:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca:ssl/record/rec_layer_s3.c:1563:SSL alert number 48
- 抓包看下警告消息为 unknown_ca
5. 总结
- 本文章对握手警告消息的含义进行了详细解释,这样在SSL/TLS握手失败时,可以通过抓包定位到大概问题。并且对于常见的握手警告消息,给出了解决方案,当然,这些都只是理论上的,实际可能需要根据日志去排查处理,但也给了大概的排查方向,可以大大提升排查问题的效率。
- 实例演示中都是在工作中实际遇到的问题,我重新把问题复现了下。后续如果遇到新握手失败的问题,会继续更新此文章。